dmc

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

commit 6b67a5dcdb2e4219c8c5b7800a8eb5af43f9b45b
parent 9bf17f2af49577e5f529dfb92bd1be543131c303
Author: pancake@localhost.localdomain <unknown>
Date:   Fri, 16 Oct 2009 19:39:05 +0200

* Added smtp.c with MX host resolution
* Add long help
* Add non-working -H flag
* Add year in copyright header
* Remove the parseoutput() function .. no longer used
Diffstat:
Makefile | 2+-
dmc | 53++++++++++++++++++++++++++++++++++++++++++++++-------
imap4.c | 2+-
pop3.c | 27++++++++++-----------------
smtp.c | 90++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
5 files changed, 147 insertions(+), 27 deletions(-)

diff --git a/Makefile b/Makefile @@ -5,7 +5,7 @@ CFLAGS?=-Wall all: dmc-smtp dmc-pop3 dmc-imap4 dmc-smtp: smtp.o - ${CC} ${LDFLAGS} smtp.o -o dmc-smtp + ${CC} ${LDFLAGS} smtp.o -o dmc-smtp -lresolv dmc-pop3: pop3.o ${CC} ${LDFLAGS} pop3.o -o dmc-pop3 diff --git a/dmc b/dmc @@ -1,15 +1,18 @@ #!/bin/sh # -# Dynamic Mail Client +# dmc - dynamic mail client +# Copyleft 2009 -- pancake <at> nopcode <dot> org # VERSION="0.1" COPYRIGHT="Copyleft -- pancake@nopcode.org" +HELP="Usage: dmc [-e acc] [-a addr] [-m addr subj] [-A file] [-s msg] [-hvdk]" [ -n "${EDITOR}" ] && EDITOR=vim mkdir -p ~/.dmc/mail mkdir -p ~/.dmc/tmp mkdir -p ~/.dmc/acc +[ -e ~/.dmc/acc.default ] && . ~/.dmc/acc.default function acc_daemon { FIFO=~/.dmc/tmp/${NAME}.fifo @@ -51,7 +54,7 @@ function print_account_template { echo "HOST=serverhost.com" echo "PORT=110" echo "#SEND=acc-name" - echo "SEND=|msmtp" + echo "SEND=!msmtp" echo "MAIL=username@domain" echo "USER='username'" echo "PASS='password'" @@ -101,10 +104,19 @@ function add_attachment { } function send_message { - if [ "`echo \"$SEND\" | grep '|'`" ]; then - echo "=> cat $1 | ${SEND}" + FILE=$1 + # TODO: find a better name for the auto mode + if [ "${SEND}" = "!msmtp" ]; then + TO="`dmc -H To < $a`" # XXX + HOST=`dmc-smtp ${TO}` # XXX + msmtp --host=localhost --port=25 --read-envelope-from --auto-from=on < $a + if [ $? = 0 ]; then + echo "Mail sent! TODO: move from out/ to sent/" + fi + elif [ "`echo \"${SEND}\" | grep '|'`" ]; then + echo "=> cat $1 ${SEND}" # TODO: setup environment for $TO $SUBJECT ... - cat $1 | ${SEND} + eval cat $1 ${SEND} else echo "SEND method '${SEND}' not supported" fi @@ -151,6 +163,20 @@ case "$1" in ;; "pull") ;; +"-H"|"--header") + FILE=$1 + [ "${FILE}" = "-" ] && FILE="" + while : ; do + shift + [ -z "$1" ] && break + grep -e : ${FILE} | grep -re ^$1 | cut -d : -f 2- + done + ;; +"-s"|"--send") + for a in $* ; do + send_message $a + done + ;; "-m"|"--mail") TO="$2" SUBJECT="$3" @@ -173,8 +199,21 @@ case "$1" in "-v"|"--version") echo "dmc v${VERSION} ${COPYRIGHT}" ;; -"--help"|"-h"|*) - echo "Usage: dmc [-e acc] [-a addr] [-m addr subj] [-A file] [-hvdk]" +"--help"|"-h") + echo ${HELP} + echo " -e account edit account information" + echo " -a name show addressbook email for contact" + echo " -m addr subj create mail with default account" + echo " -H header grep for header" + echo " -A file add attachment to mail" + echo " -s file send email" + echo " -d start daemon" + echo " -h show this help message" + echo " push send mails in box/*/out" + echo " pull update box/*/in folders" + ;; +*) + echo "Usage: dmc [-e acc] [-a addr] [-m addr subj] [-A file] [-s msg] [-hvdk]" ;; esac diff --git a/imap4.c b/imap4.c @@ -1,4 +1,4 @@ -/* dmc :: Copyleft -- pancake (at) nopcode (dot) org */ +/* dmc :: Copyleft 2009 -- pancake (at) nopcode (dot) org */ #include <stdio.h> #include <string.h> diff --git a/pop3.c b/pop3.c @@ -1,4 +1,4 @@ -/* dmc :: Copyleft -- pancake (at) nopcode (dot) org */ +/* dmc :: Copyleft 2009 -- pancake (at) nopcode (dot) org */ #include <stdio.h> #include <string.h> @@ -108,13 +108,6 @@ static int doword(char *word) { return ret; } -static void parseoutput(void) { - while(!feof(stdin)) { - sleep(1); - printf("TODO\n"); - } -} - static void cleanup(int foo) { close(ff); unlink(fifo); @@ -122,18 +115,18 @@ static void cleanup(int foo) { } int main(int argc, char **argv) { + int ret = 0; if (argc>1) { signal(SIGINT, cleanup); fifo = argv[1]; mkfifo(fifo, 0600); ff = open(fifo, O_RDONLY); - if (ff == -1) { - fprintf(stderr, "Cannot open fifo file.\n"); - return 1; - } - waitreply(1); - while(doword(getword())); - cleanup(0); - } else parseoutput(); - return 0; + if (ff != -1) { + waitreply(1); + while(doword(getword())); + cleanup(0); + ret = 0; + } else fprintf(stderr, "Cannot open fifo file.\n"); + } else fprintf(stderr, "Usage: dmc-pop3 fifo | nc host 110 > fifo\n"); + return ret; } diff --git a/smtp.c b/smtp.c @@ -1,3 +1,91 @@ -int main() { +/* dmc :: Copyleft 2009 -- pancake (at) nopcode (dot) org */ + +#include <stdio.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <netinet/in.h> +#include <sys/types.h> +#include <arpa/nameser.h> +#include <resolv.h> +#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; + + 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; + } + + /* 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; + } + + 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; +} + +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; }