dmc

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

commit 26014c6ffb0b3a3a446e837eaa931534b39e8e1b
parent b786fbad54ce8d965e324721e1736b40ab830009
Author: pancake@localhost.localdomain <unknown>
Date:   Sun,  1 Nov 2009 20:58:22 +0100

* Initial non usable SSL support in sock.c (imap+pop3)
* Adapt 'dmc' start and -c commands to the new pipeline
* Adapt imap4 to the new pipeline format
  - Make it work again
  - Fix read lock
Diffstat:
Makefile | 10++++++++--
README | 4+---
config.def.h | 2+-
config.mk | 1+
dmc | 47+++++++----------------------------------------
doc/send | 13+++++++++++++
imap4.c | 109+++++++++++++++++++++++++++++++------------------------------------------------
pop3.c | 19++++++++++---------
sock.c | 39+++++++++++++++++++++++++++++++++++++--
9 files changed, 121 insertions(+), 123 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,20 +1,26 @@ include config.mk +ifeq ($(HAVE_SSL),1) +SSL_LIBS=`pkg-config libssl --libs` +CFLAGS+=`pkg-config libssl --cflags` +endif + all: config.h dmc-smtp dmc-pop3 dmc-imap4 dmc-pack config.h: @echo creating $@ from config.def.h cp config.def.h config.h + ${MAKE} clean dmc-smtp: smtp.o ${CC} ${LDFLAGS} smtp.o -o dmc-smtp -lresolv # sock.c ? dmc-pop3: pop3.o - ${CC} ${LDFLAGS} pop3.o -o dmc-pop3 + ${CC} ${LDFLAGS} ${SSL_LIBS} pop3.o -o dmc-pop3 dmc-imap4: imap4.o - ${CC} ${LDFLAGS} imap4.o -o dmc-imap4 + ${CC} ${LDFLAGS} ${SSL_LIBS} imap4.o -o dmc-imap4 dmc-pack: pack.o ${CC} ${LDFLAGS} pack.o -o dmc-pack diff --git a/README b/README @@ -5,9 +5,7 @@ dmc is a minimalist email client solution Requirements ------------ - netcat (nc) for plain TCP connections - openssl binary for SSL encrypted - msmtp if you want to use + msmtp to send emails (dmc-smtp is not implemented yet) Installation diff --git a/config.def.h b/config.def.h @@ -1 +1 @@ -#define HAVE_SSL 0 +#define HAVE_SSL 1 diff --git a/config.mk b/config.mk @@ -2,5 +2,6 @@ VERSION = 0.1 PREFIX ?= /usr CFLAGS ?= -Wall +HAVE_SSL=1 CC ?= gcc diff --git a/dmc b/dmc @@ -15,57 +15,24 @@ mkdir -p ~/.dmc/acc [ -e ~/.dmc/acc.default ] && . ~/.dmc/acc.default function acc_daemon { - FIFO=~/.dmc/tmp/${NAME}.fifo - OUTF=~/.dmc/tmp/${NAME}.out + LOCK=~/.dmc/tmp/${NAME}.lock INPUT=~/.dmc/tmp/${NAME}.input OUTPUT=~/.dmc/tmp/${NAME}.output - if [ "${SSL}" = 1 ]; then - NETCMD="openssl s_client -quiet -host $HOST -port $POST" - # TODO: Add decent support for certification check and reviewing - # First connection must store the certificate in ~/.dmc/acc/ssl.cert - # NETCMD="openssl s_client -cert '${CERT}' -verify 1 -quiet -host $HOST -port $POST" - else - NETCMD="nc $HOST $PORT" - fi - echo "Starting $NAME account daemon..." - rm -f "${INPUT}" "${FIFO}" "${OUTF}" - mkfifo "${INPUT}" "${FIFO}" -# XXX output must be also a fifo?!? - :> ${OUTF} + rm -f "${LOCK}" "${INPUT}" "${OUTPUT}" + mkfifo "${LOCK}" "${INPUT}" echo login ${USER} ${PASS} > ${INPUT} & (while : ; do cat ${INPUT} 2> /dev/null ; done) | \ - dmc-${PROTOCOL} ${FIFO} ${OUTF} 2> ${OUTPUT} | $NETCMD > $FIFO - rm -f ${INPUT} + dmc-${PROTOCOL} ${HOST} ${PORT} ${SSL} 2> ${OUTPUT} > ${LOCK} + rm -f "${LOCK}" "${INPUT}" "${OUTPUT}" } function dmc_cmd { -# while not 0x00 is found...sleep 1 - #:> ~/.dmc/tmp/${NAME}.output - # XXX this is going to fail and lock - OUT=~/.dmc/tmp/${NAME}.output - :> ${OUT} echo "$@" > ~/.dmc/tmp/${NAME}.input - # XXX ultraugly way to check for eof - cat ~/.dmc/tmp/${NAME}.output # barrier - cat ${OUT} - osize=0 - while : ; do - size=`du -hs ${OUT}|awk '{print $1}'` - if [ "$size" = 0 ]; then - sleep 1 - else - if [ "$size" = "$osize" ]; then - break - else - sleep 1 - osize=$size - fi - fi - done - cat ${OUT} + head -n 1 ~/.dmc/tmp/${NAME}.lock + cat ~/.dmc/tmp/${NAME}.output } function start_account_daemons { diff --git a/doc/send b/doc/send @@ -0,0 +1,13 @@ +dmc-send +======== + +send methods (in config.h?) + - mbox write + - maildir write + - |mail + - |msmtp + - MX + connect (auto smtp) + - nc localhost 25 + +Must support more than one chained send methods + - to move a mail into the sent folder f.ex? diff --git a/imap4.c b/imap4.c @@ -9,13 +9,11 @@ #include <unistd.h> #include <sys/stat.h> #include <sys/types.h> - +#include "sock.c" static char *cmd = NULL; static char word[4096]; static int ctr = 1; -static char *fifo, *outf; -static int ff, fo; static char *dir; /* TODO: make getword() ready() and cleanup() shared between smtp,pop,imap? */ @@ -55,35 +53,25 @@ reread: return word; } -static void cleanup(int foo) { - close(ff); - unlink(fifo); - exit(0); -} - -static int ready() { - struct pollfd fds[1]; - fds[0].fd = ff; - fds[0].events = POLLIN|POLLPRI; - fds[0].revents = POLLNVAL|POLLHUP|POLLERR; - return poll((struct pollfd *)&fds, 1, 10); +static void cleanup (void) { + sock_close (); + exit (0); } static int waitreply() { char *ptr, *str = word; int lock = 1; int line = 0; - int ret, reply = -1; + int reply = -1; char result[256]; - ftruncate (fo, 0); - while(lock || !ready()) { + + ftruncate (2, 0); + *str = 0; + result[0] = '\0'; + while(lock || sock_ready()) { lock = 0; - ret = read(ff, str, 1024); - if (ret<1) { - fprintf(stderr, " BREAK BREAK\n"); + if (sock_read (str, 2024) <1) break; - } - str[ret] = 0; if (line == 0) { ptr = strchr(word, ' '); if (ptr) { @@ -96,19 +84,14 @@ static int waitreply() { if (!memcmp(ptr+1, "BAD", 3)) reply = 0; } - // XXX: Fix output, just show first line - snprintf(result, 254, "### %s %d \"%s\"\n", cmd, reply, str); + snprintf (result, 254, "### %s %d \"%s\"\n", cmd, reply, str); } str = str+strlen(str); line++; - write (fo, str, strlen (str)); - // fprintf(stderr, "--> %s\n", str); } - //fprintf (stderr, "==> (((%s)))\n", word); - write (fo, word, strlen (word)); - //fflush (stderr); - write (2, result, strlen(result)); + write (2, word, strlen (word)); + write (1, result, strlen(result)); return reply; } @@ -121,7 +104,7 @@ CLOSE - commit the delete stuff (maybe must be done after rm) EXPUNGE - permanent remove of deltec RECENT - show the number of recent messages #endif -static int doword(char *word) { +static int doword (char *word) { int ret = 1; free (cmd); cmd = strdup(word); @@ -129,12 +112,12 @@ static int doword(char *word) { /* Do nothing */ } else if (!strcmp(word, "exit")) { - printf("%d LOGOUT\n", ctr++); + sock_printf("%d LOGOUT\n", ctr++); waitreply(); ret = 0; } else if (!strcmp(word, "help") || !strcmp(word, "?")) { - fprintf(stderr, "Use: login exit find ls cat head rm rmdir mkdir mvdir\n"); + fprintf(stderr, "Use: login exit find cd pwd ls cat head rm rmdir mkdir mvdir\n"); } else if (!strcmp(word, "pwd")) { fprintf(stderr, "%s\n", dir); @@ -144,38 +127,37 @@ static int doword(char *word) { dir = strdup(getword()); if (!strcmp(dir, "\"\"")) *dir=0; - printf("%d SELECT \"%s\"\n", ctr++, dir); + sock_printf ("%d SELECT \"%s\"\n", ctr++, dir); waitreply(); } else if (!strcmp(word, "find")) { - printf("%d SEARCH TEXT \"%s\"\n", ctr++, getword()); + sock_printf ("%d SEARCH TEXT \"%s\"\n", ctr++, getword()); waitreply(); } else if (!strcmp(word, "ls")) { - printf("%d LIST \"%s\" *\n", ctr++, dir); + sock_printf ("%d LIST \"%s\" *\n", ctr++, dir); waitreply(); } else if (!strcmp(word, "cat")) { - printf("%d FETCH %d body[]\n", + sock_printf ("%d FETCH %d body[]\n", ctr++, atoi(getword())); waitreply(); } else if (!strcmp(word, "head")) { - printf("%d FETCH %d body[header]\n", + sock_printf ("%d FETCH %d body[header]\n", ctr++, atoi(getword())); waitreply(); } else if (!strcmp(word, "mvdir")) { - printf("%d RENAME %s %s\n", + sock_printf ("%d RENAME %s %s\n", ctr++, getword(), getword()); } else if (!strcmp(word, "mkdir")) { - printf("%d CREATE \"%s\"\n", - ctr++, getword()); + sock_printf ("%d CREATE \"%s\"\n", ctr++, getword()); } else if (!strcmp(word, "rm")) { - printf("%d DELE %d\n", ctr++, atoi(getword())); - waitreply(); + sock_printf ("%d DELE %d\n", ctr++, atoi(getword())); + waitreply (); } else if (!strcmp(word, "rmdir")) { printf("%d DELETE \"%s\"\n", @@ -183,37 +165,32 @@ static int doword(char *word) { waitreply(); } else if (!strcmp(word, "login")) { - char *user = strdup(getword()); - char *pass = strdup(getword()); - printf("%d LOGIN \"%s\" \"%s\"\n", + char *user = strdup (getword ()); + char *pass = strdup (getword ()); + sock_printf ("%d LOGIN \"%s\" \"%s\"\n", ctr++, user, pass); - free(user); - free(pass); + free (user); + free (pass); waitreply(); } else { - printf("%d NOOP\n", ctr++); + sock_printf ("%d NOOP\n", ctr++); waitreply(); } return ret; } -int main(int argc, char **argv) { - int ret = 0; +int main (int argc, char **argv) { + int ssl = 0, ret = 0; if (argc>2) { - signal(SIGINT, cleanup); - fifo = argv[1]; - outf = argv[2]; - mkfifo (fifo, 0600); - unlink (outf); - ff = open (fifo, O_RDONLY); - fo = open (outf, O_WRONLY|O_CREAT, 0600); - if (ff != -1 && fo != -1) { - dir = strdup(""); - waitreply(); - while(doword(getword())); - cleanup(0); + if (argc>3) + ssl = (*argv[3]=='1'); + if (sock_connect (argv[1], atoi (argv[2]), ssl) >= 0) { ret = 0; - } else fprintf(stderr, "Cannot open fifo file.\n"); - } else fprintf(stderr, "Usage: dmc-imap4 fifo-in fifo-out | nc host 443 > fifo\n"); + atexit (cleanup); + waitreply (); + dir = strdup (""); + while (doword (getword())); + } else fprintf (stderr, "Cannot connect to %s %d\n", argv[1], atoi(argv[2])); + } else fprintf(stderr, "Usage: dmc-imap4 host port 2> body > fifo < input\n"); return ret; } diff --git a/pop3.c b/pop3.c @@ -22,7 +22,7 @@ static char *getword () { } static int waitreply() { - char result[1024]; + char result[256]; char *ch, *str = word; int lock = 1; int reply = -1; @@ -47,16 +47,16 @@ static int waitreply() { } } // TODO: \r \n issues - ch = strstr(str, "\r\n."); + ch = strstr (str, "\r\n."); if (ch) *ch = '\0'; //fprintf(stderr, "%s\n", str); fputs (str, stderr); } - fputs("", stderr); - fflush(stderr); + fputs ("", stderr); + fflush (stderr); fputs (result, stdout); - fflush(stdout); + fflush (stdout); /* stderr lseek works on pipes :D */ lseek (2, 0, 0); return reply; @@ -109,15 +109,16 @@ static void cleanup (void) { } int main(int argc, char **argv) { - int ret = 1; + int ssl = 0, ret = 1; if (argc>2) { - if (sock_connect (argv[1], atoi (argv[2])) >= 0) { + if (argc>3) + ssl = (*argv[3]=='1'); + if (sock_connect (argv[1], atoi (argv[2]), ssl) >= 0) { ret = 0; atexit (cleanup); waitreply (); while (doword (getword())); - cleanup (); } else fprintf (stderr, "Cannot connect to %s %d\n", argv[1], atoi(argv[2])); - } else fprintf (stderr, "Usage: dmc-pop3 host port 2> body > fifo < input\n"); + } else fprintf (stderr, "Usage: dmc-pop3 host port [ssl] 2> body > fifo < input\n"); return 0; } diff --git a/sock.c b/sock.c @@ -13,15 +13,36 @@ #if HAVE_SSL #include <openssl/ssl.h> static int ssl = 0; +static SSL_CTX *ctx; +static SSL *sfd; #endif 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; +#else + return 0; +#endif +} + // TODO: cleanup all those fd=-1 -int sock_connect (const char *host, int port) { +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; @@ -49,10 +70,18 @@ static int sock_ready() { } int sock_close () { +#if HAVE_SSL + SSL_free (sfd); +#endif return close (fd); } int sock_write (const char *str) { +#if HAVE_SSL + if (ssl) + return SSL_write (sfd, str, strlen(str)); + else +#endif return write (fd, str, strlen(str)); } @@ -69,7 +98,13 @@ int sock_printf (const char *fmt, ...) { } int sock_read (char *buf, int len) { - int ret = read (fd, buf, 1024); + int ret; +#if HAVE_SSL + if (ssl) + ret = SSL_read (sfd, buf, 1024); + else +#endif + ret = read (fd, buf, 1024); if (ret>0) buf[ret] = '\0'; return ret;