dmc

dynamic mail client
git clone git://git.suckless.org/dmc
Log | Files | Refs | README | LICENSE

commit 1628ee23e1202be018894a0d9e0b23f1dd6329a1
parent 109860e2aef53382f2c6c65747f03b95706f3d6c
Author: pancake@localhost.localdomain <unknown>
Date:   Fri,  6 Nov 2009 21:13:06 +0100

* Various syntax fixes
* Add LICENSE and HISTORY files
Diffstat:
HISTORY | 9+++++++++
LICENSE | 22++++++++++++++++++++++
dmc | 34+++++++++++++++++-----------------
filter.c | 4++--
mbox.c | 42+++++++++++++++++++-----------------------
pop3.c | 3+--
smtp.c | 133++++++++++++++++++++++++++++++++++++++-----------------------------------------
sock.c | 128++++++++++++++++++++++++++++++++++++++++----------------------------------------
8 files changed, 198 insertions(+), 177 deletions(-)

diff --git a/HISTORY b/HISTORY @@ -0,0 +1,9 @@ +dmc history +=========== + +dmc was born as a proof of concept for a suckless email client after some +discussions in the dev@ mailing list of www.suckless.org project. + +The first mail with ideas was sent in 2009-10-06. + +First usable release (0.1) was released in XXXX-XX-XX diff --git a/LICENSE b/LICENSE @@ -0,0 +1,22 @@ +MIT/X Consortium License + +© 2009 pancake <pancake at nopcode dot org> +© 2009 nibble <nibble at gmail dot com> + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/dmc b/dmc @@ -1,6 +1,7 @@ #!/bin/sh -# dmc - dynamic mail client -# Copyleft 2009 -- pancake <at> nopcode <dot> org +# See LICENSE file for copyright and license details. +#--- +# dmc - dynamic mail client - pancake <at> nopcode <dot> org VERSION="0.1" COPYRIGHT="Copyleft -- pancake@nopcode.org" @@ -41,7 +42,7 @@ start_account_daemons () { i=$(($i+1)) sleep 1 done - if [ "$i" = 0 ]; then + if [ $i = 0 ]; then echo "No accounts defined in ~/.dmc/acc" exit 1 fi @@ -56,6 +57,7 @@ print_account_template () { echo "PORT=110" echo "#SEND=acc-name" echo "SEND=!msmtp" + echo "ONLINE=0" echo "MAIL=username@domain" echo "USER='username'" echo "PASS='password'" @@ -171,20 +173,18 @@ case "$1" in "push") for a in ~/.dmc/acc/* ; do . $a - if [ -d ~/.dmc/box/${NAME}/out ]; then - for b in ~/.dmc/box/${NAME}/out/* ; do - if [ -f "$b" ]; then - send_message "$b" - if [ $? = 0 ]; then - echo "Mail sent. local copy moved to ~/.dmc/box/${NAME}/sent" - mkdir -p ~/.dmc/box/${NAME}/sent - mv $b ~/.dmc/box/${NAME}/sent - else - echo "There was an error while sending the mail" - fi - fi - done - fi + [ ! -d ~/.dmc/box/${NAME}/out ] && continue + for b in ~/.dmc/box/${NAME}/out/* ; do + [ ! -f "$b" ] && continue + send_message "$b" + if [ $? = 0 ]; then + echo "Mail sent. local copy moved to ~/.dmc/box/${NAME}/sent" + mkdir -p ~/.dmc/box/${NAME}/sent + mv $b ~/.dmc/box/${NAME}/sent + else + echo "There was an error sending the mail" + fi + done done ;; "pull") diff --git a/filter.c b/filter.c @@ -10,12 +10,12 @@ int main(int argc, char **argv) { for (i = 0; i < argc; i++) if (!strcmp (argv[i], "-h")) { - fprintf (stderr, "Usage: %s [-h] [headers | :] [-e] [new headers] < mail\n", argv[0]); + printf ("Usage: %s [-h] [headers | :] [-e] [new headers] < mail\n", argv[0]); return 1; } else if (!strcmp (argv[i], "-e")) edit = i; for (i = 0; i < argc; i++) { - strncpy(argv2[i], argv[i], 1023); + strncpy (argv2[i], argv[i], 1023); argv2[i][1023] = '\0'; } memset (b, '\0', 1024); diff --git a/mbox.c b/mbox.c @@ -8,13 +8,14 @@ FILE *fd; static char word[1024]; -static void mbox_ls () { +// XXX maybe so many [1024] stuff. can this cause truncated mails? +static void mbox_ls() { char b[1024], from[1024], subject[1024], date[1024], *ptr; int m = 0, headers = 1; b[1023] = '\0'; fseek (fd, 0, SEEK_SET); - while(fgets (b, 1023, fd)) { + while (fgets (b, 1023, fd)) { if (b[0]=='\n') { if (headers) { printf ("%i %s %s %s\n", m++, from, date, subject); @@ -48,23 +49,21 @@ static void mbox_ls () { } } -static void mbox_cat (int idx, int body) { +static void mbox_cat(int idx, int body) { char b[1024]; int m = 0, headers = 1; b[1023] = '\0'; fseek (fd, 0, SEEK_SET); - while(fgets (b, 1023, fd)) { + while (fgets (b, 1023, fd)) { if (b[0]=='\n') { - if (headers) - headers = 0; - else { + if (!headers) { fgets (b, 1023, fd); if (!memcmp (b, "From ", 5)) { headers = 1; m++; } - } + } else headers = 0; } if (m == idx && (headers || body)) fputs (b, stdout); @@ -76,36 +75,34 @@ static void mbox_rm (int idx) { int m = 0, i = 0, headers = 1, size; fseek(fd, 0, SEEK_END); - size = ftell(fd); + size = ftell (fd); if (!(buf = malloc (size))) return; b[1023] = '\0'; fseek (fd, 0, SEEK_SET); - while(fgets (b, 1023, fd)) { + while (fgets (b, 1023, fd)) { if (b[0]=='\n') { - if (headers) - headers = 0; - else { + if (!headers) { fgets (b, 1023, fd); if (!memcmp (b, "From ", 5)) { headers = 1; if (++m == idx) { - strcpy(buf + i, "\n"); + strcpy (buf + i, "\n"); i += 1; } } - } + } else headers = 0; } if (m != idx) { - strcpy(buf + i, b); - i += strlen(b); + strcpy (buf + i, b); + i += strlen (b); } } fseek (fd, 0, SEEK_SET); fwrite (buf, 1, i, fd); fflush (fd); - ftruncate (fileno(fd), i); - free(buf); + ftruncate (fileno (fd), i); + free (buf); } static char *getword () { @@ -146,10 +143,9 @@ int main (int argc, char **argv) { if (argc>1) { fd = fopen (argv[1], "r+"); if (fd != NULL) { - ret = 0; while (doword (getword ())); - fclose (fd); - } else fprintf (stderr, "Cannot open %s\n", argv[1]); - } else fprintf (stderr, "Usage: dmc-mbox [mbox-file] 2> body > fifo < input\n"); + ret = fclose (fd); + } else printf ("Cannot open %s\n", argv[1]); + } else printf ("Usage: dmc-mbox [mbox-file] 2> body > fifo < input\n"); return ret; } diff --git a/pop3.c b/pop3.c @@ -107,8 +107,7 @@ int main(int argc, char **argv) { if (argc>3) ssl = (*argv[3]=='1'); if (sock_connect (argv[1], atoi (argv[2]), ssl) >= 0) { - ret = 0; - atexit (sock_close); + ret = atexit (sock_close); waitreply (1); while (doword (getword ())); } else printf ("Cannot connect to %s %d\n", argv[1], atoi(argv[2])); diff --git a/smtp.c b/smtp.c @@ -11,81 +11,76 @@ #define BIND_4_COMPAT static int resmx(const char *domain) { - char host[NS_MAXDNAME+1]; - char last[NS_MAXDNAME+1]; - typedef union { - HEADER head; - char buf[PACKETSZ]; - } pkt_t; - unsigned char buf[PACKETSZ]; - unsigned char *rrptr; - pkt_t *pkt = (pkt_t *)buf; - int querylen, len, n, exprc; - int rrtype, antrrtype; - int rrpayloadsz; + char host[NS_MAXDNAME+1]; + char last[NS_MAXDNAME+1]; + typedef union { + HEADER head; + char buf[PACKETSZ]; + } pkt_t; + unsigned char buf[PACKETSZ]; + unsigned char *rrptr; + pkt_t *pkt = (pkt_t *)buf; + int querylen, len, n, exprc; + int rrtype, antrrtype; + int rrpayloadsz; - querylen = res_querydomain(domain, "", C_IN,T_MX, - (void*)&buf, PACKETSZ); + querylen = res_querydomain (domain, "", C_IN,T_MX, (void*)&buf, PACKETSZ); - if (ntohs(pkt->head.rcode) == NOERROR) { - n = ntohs(pkt->head.ancount); - if (n==0) { - fprintf(stderr, "No MX found\n"); - return 1; - } + if (ntohs (pkt->head.rcode) == NOERROR) { + n = ntohs (pkt->head.ancount); + if (n==0) { + fprintf(stderr, "No MX found\n"); + return 1; + } - /* expand DNS query */ - len = dn_expand( buf, - buf+querylen, buf+sizeof(HEADER), - host, sizeof(host)); + /* expand DNS query */ + len = dn_expand (buf, + buf + querylen, buf + sizeof(HEADER), + host, sizeof (host)); + if (len<0) { + fprintf (stderr, "No MX found\n"); + return 1; + } - if (len<0) { - fprintf(stderr, "No MX found\n"); - return 1; - } + rrptr = buf + len + 4 + sizeof (HEADER); - rrptr = buf+sizeof(HEADER)+4+len; - - while(rrptr < buf+querylen) { - /* expand NAME resolved */ - exprc = dn_expand(buf,buf+querylen,rrptr,host,sizeof(host)); - if (exprc<0) { - fprintf(stderr, "No MX found\n"); - return 1; - } - rrptr += exprc; - rrtype = (rrptr[0]<<8|rrptr[1]); - rrpayloadsz = (rrptr[8]<<8|rrptr[9]); - rrptr += 10; - switch(rrtype) { - /* TODO support for IPv6: case T_AAAA: */ - case T_A: - if (strcmp(host, last)) { - printf("%s\n", host); - if (--n==0) querylen=0; - } - break; - } - antrrtype = rrtype; - rrptr += rrpayloadsz; - } - } else { - printf("%s\n", domain); - //fprintf(stderr, "No MX found\n"); - return 1; - } - return 0; + while (rrptr < buf+querylen) { + /* expand NAME resolved */ + exprc = dn_expand (buf, buf+querylen, rrptr, host, sizeof (host)); + if (exprc<0) { + fprintf (stderr, "No MX found\n"); + return 1; + } + rrptr += exprc; + rrtype = (rrptr[0]<<8|rrptr[1]); + rrpayloadsz = (rrptr[8]<<8|rrptr[9]); + rrptr += 10; + switch (rrtype) { + /* TODO support for IPv6: case T_AAAA: */ + case T_A: + if (strcmp (host, last)) { + printf ("%s\n", host); + if (--n==0) querylen=0; + } + break; + } + antrrtype = rrtype; + rrptr += rrpayloadsz; + } + } else { + printf ("%s\n", domain); + return 1; + } + return 0; } int main(int argc, char **argv) { - if (argc>1) { - char *ch = strchr(argv[1], '@'); - if (ch) return resmx(ch+1); - else { - /* do the daemon stuff here */ - fprintf(stderr, "TODO: SMTP protocol not yet implemented\n"); - } - } else printf("Usage: dmc-smtp [user@domain] # Get MX for domain\n" - "Usage: dmc-smtp fifo | nc host 25 > fifo\n"); - return 0; + if (argc>1) { + char *ch = strchr(argv[1], '@'); + if (!ch) { + /* do the daemon stuff here */ + fprintf (stderr, "TODO: SMTP protocol not yet implemented\n"); + } else return resmx (ch+1); + } else printf ("Usage: dmc-smtp [user@domain] # Get MX for domain\n"); + return 0; } diff --git a/sock.c b/sock.c @@ -20,91 +20,91 @@ static int fd = -1; int sock_ssl (int enable) { #if HAVE_SSL - int err; - if (ssl) { - // challenge, check cert, etc.. - sfd = SSL_new (ctx); - SSL_set_fd (sfd, fd); - err = SSL_connect (sfd); - /* TODO: check cert */ - SSL_set_accept_state (sfd); - } - ssl = enable; - return 1; + int err; + if (ssl) { + // challenge, check cert, etc.. + sfd = SSL_new (ctx); + SSL_set_fd (sfd, fd); + err = SSL_connect (sfd); + /* TODO: check cert */ + SSL_set_accept_state (sfd); + } + ssl = enable; + return 1; #else - return 0; + return 0; #endif } // TODO: cleanup all those fd=-1 -int sock_connect (const char *host, int port, int ssl) { - struct sockaddr_in sa; - struct hostent *he; - int s = socket (AF_INET, SOCK_STREAM, 0); - sock_ssl (ssl); - fd = -1; - if (s != -1) { - fd = s; - memset (&sa, 0, sizeof (sa)); - sa.sin_family = AF_INET; - he = (struct hostent *)gethostbyname (host); - if (he != (struct hostent*)0) { - sa.sin_addr = *((struct in_addr *)he->h_addr); - sa.sin_port = htons (port); - if (connect (fd, (const struct sockaddr*)&sa, sizeof (struct sockaddr))) - fd = -1; - } else fd = -1; - if (fd == -1) - close (s); - } else fd = -1; - return fd; +int sock_connect(const char *host, int port, int ssl) { + struct sockaddr_in sa; + struct hostent *he; + int s = socket (AF_INET, SOCK_STREAM, 0); + sock_ssl (ssl); + fd = -1; + if (s != -1) { + fd = s; + memset (&sa, 0, sizeof (sa)); + sa.sin_family = AF_INET; + he = (struct hostent *)gethostbyname (host); + if (he != (struct hostent*)0) { + sa.sin_addr = *((struct in_addr *)he->h_addr); + sa.sin_port = htons (port); + if (connect (fd, (const struct sockaddr*)&sa, sizeof (struct sockaddr))) + fd = -1; + } else fd = -1; + if (fd == -1) + close (s); + } else fd = -1; + return fd; } static int sock_ready() { - struct pollfd fds[1]; - fds[0].fd = fd; - fds[0].events = POLLIN|POLLPRI; - fds[0].revents = POLLNVAL|POLLHUP|POLLERR; - return poll((struct pollfd *)&fds, 1, 10); + struct pollfd fds[1]; + fds[0].fd = fd; + fds[0].events = POLLIN|POLLPRI; + fds[0].revents = POLLNVAL|POLLHUP|POLLERR; + return poll((struct pollfd *)&fds, 1, 10); } -void sock_close () { +void sock_close() { #if HAVE_SSL - SSL_free (sfd); + SSL_free (sfd); #endif - close (fd); + close (fd); } -int sock_write (const char *str) { +int sock_write(const char *str) { #if HAVE_SSL - if (ssl) - return SSL_write (sfd, str, strlen(str)); - else + if (ssl) + return SSL_write (sfd, str, strlen(str)); + else #endif - return write (fd, str, strlen(str)); + return write (fd, str, strlen(str)); } -int sock_printf (const char *fmt, ...) { - va_list ap; - int ret = -1; - char buf[1024]; - va_start (ap, fmt); - vsnprintf (buf, 1023, fmt, ap); - // XXX check len - ret = sock_write (buf); - va_end (ap); - return ret; +int sock_printf(const char *fmt, ...) { + va_list ap; + int ret = -1; + char buf[1024]; + va_start (ap, fmt); + vsnprintf (buf, 1023, fmt, ap); + // XXX check len + ret = sock_write (buf); + va_end (ap); + return ret; } int sock_read (char *buf, int len) { - int ret; + int ret; #if HAVE_SSL - if (ssl) - ret = SSL_read (sfd, buf, len); - else + if (ssl) + ret = SSL_read (sfd, buf, len); + else #endif - ret = read (fd, buf, len); - if (ret>0) - buf[ret] = '\0'; - return ret; + ret = read (fd, buf, len); + if (ret>0) + buf[ret] = '\0'; + return ret; }