dmc

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

commit 81d064290c5a4f18ce59e165ed81b82d320ac61e
parent 4a2d861498b554c60ee70a4ede1cf4750bcfaacd
Author: pancake@localhost.localdomain <unknown>
Date:   Mon, 12 Oct 2009 18:37:14 +0200

* Move makefile to the root of the project
* Added a decent README and the wip mails in doc/
Diffstat:
Makefile | 32++++++++++++++++++++++++++++++++
README | 107+++++++++++++++++++++++++++++++++++--------------------------------------------
TODO | 1-
dmc | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
dmc.1 | 1+
doc/random | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
doc/wipmail.txt | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
doc/wipmail2.txt | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
imap4.c | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
pop3.c | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
smtp.c | 3+++
src/Makefile | 32--------------------------------
src/dmc | 97-------------------------------------------------------------------------------
src/imap4.c | 107-------------------------------------------------------------------------------
src/pop3.c | 139-------------------------------------------------------------------------------
src/smtp.c | 3---
16 files changed, 657 insertions(+), 439 deletions(-)

diff --git a/Makefile b/Makefile @@ -0,0 +1,32 @@ +CC?=gcc +PREFIX?=/usr +CFLAGS?=-Wall + +all: dmc-smtp dmc-pop3 dmc-imap4 + +dmc-smtp: smtp.o + ${CC} ${LDFLAGS} smtp.o -o dmc-smtp + +dmc-pop3: pop3.o + ${CC} ${LDFLAGS} pop3.o -o dmc-pop3 + +dmc-imap4: imap4.o + ${CC} ${LDFLAGS} imap4.o -o dmc-imap4 + +install: + cp -f dmc ${PREFIX}/bin + cp -f dmc-smtp ${PREFIX}/bin + cp -f dmc-pop3 ${PREFIX}/bin + cp -f dmc-imap4 ${PREFIX}/bin + +uninstall: + rm -f ${PREFIX}/bin/dmc + rm -f ${PREFIX}/bin/dmc-smtp + rm -f ${PREFIX}/bin/dmc-pop3 + rm -f ${PREFIX}/bin/dmc-imap4 + +clean: + rm -f dmc-pop3 dmc-imap4 dmc-smtp *.o + +loc: + sloccount . diff --git a/README b/README @@ -1,61 +1,48 @@ - +-----+---------------------+ - | DMC | Dynamic Mail Client | - +-----+---------------------+ - -Sending mails: --------------- - dmc-smtp ~/mail/outbox/001.eml - [ $? = 0 ] && mv ~/mail/outbox/001.* ~/mail/sent/ - - -IMAP handling: --------------- - Usage: dmc-imap [options] [host] [port] < commands > output - dmc-imap -a plain -d ~/mail [host] [port] - - options: - -a : auth method - -d : base user mail directory - - commands: - cd [folder] - # SELECT "folder" - 1003 [20:47:15] IMAP4> 51 SELECT "Sent Messages" - 1004 [20:47:15] IMAP4< * FLAGS (\Answered \Flagged \Deleted \Seen \Draft $Forwarded) - 1005 [20:47:15] IMAP4< * OK [PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft $Forwarded \*)] Flags permitted. - 1006 [20:47:15] IMAP4< * 340 EXISTS - 1007 [20:47:15] IMAP4< * 2 RECENT - 1008 [20:47:15] IMAP4< * OK [UIDVALIDITY 1230118148] UIDs valid - 1009 [20:47:15] IMAP4< * OK [UIDNEXT 341] Predicted next UID - 1010 [20:47:15] IMAP4< 51 OK [READ-WRITE] Select completed. - - st : show status - 2508 [20:48:11] IMAP4> 60 STATUS "Spam.learn-ham" (MESSAGES UIDNEXT UIDVALIDITY UNSEEN) - 2509 [20:48:12] IMAP4< * STATUS "Spam.learn-ham" (MESSAGES 0 UIDNEXT 1 UIDVALIDITY 1211795420 UNSEEN 0) - 2510 [20:48:12] IMAP4< 60 OK Status completed. - - ls [num] : list num mails (can be used to check for new mail) - cp = copy a mail from one folder to other - mv = copy+remove - rm = remove mail - lt = list folder tree - -LOGIN - Example: C: a001 LOGIN SMITH SESAME - S: a001 OK LOGIN completed -SELECT - Example: C: A142 SELECT INBOX - S: * 172 EXISTS - S: * 1 RECENT - S: * OK [UNSEEN 12] Message 12 is first unseen - S: * OK [UIDVALIDITY 3857529045] UIDs valid - S: * OK [UIDNEXT 4392] Predicted next UID - S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft) - S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited - S: A142 OK [READ-WRITE] SELECT completed -CREATE - Example: C: A003 CREATE owatagusiam/ - S: A003 OK CREATE completed - C: A004 CREATE owatagusiam/blurdybloop - S: A004 OK CREATE completed +dmc - dynamic mail client +========================= +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 + + +Installation +------------ +Few binaries will be copied into the bin directory + + make all install PREFIX=/usr + + +Configuration +------------- +Accounting information is stored in ~/.dmc/acc and can be +edited with + + dmc -e myaccount + +Running +------- +Start it in daemon mode + + dmc -d + +To send a mail add the contact to your addressbook + + echo 'user <foo@bar.com>' > ~/.dmc/addrbook + + or edit the addressbook + + dmc -a + +Then type the mail: + + XXX: This is not correct + +Add attachments: + + $EDITOR msg + dmc-mime msg attach1.zip | dmc -m `dmc -a user` diff --git a/TODO b/TODO @@ -1 +0,0 @@ -* --stop and pid registration is broken diff --git a/dmc b/dmc @@ -0,0 +1,97 @@ +#!/bin/sh +# +# Dynamic Mail Client +# + +VERSION="0.1" +COPYRIGHT="Copyleft -- pancake@nopcode.org" + +[ -n "${EDITOR}" ] && EDITOR=vim +mkdir -p ~/.dmc/mail +mkdir -p ~/.dmc/tmp +mkdir -p ~/.dmc/acc + +function acc_daemon { + FIFO=~/.dmc/tmp/${NAME}.fifo + INPUT=~/.dmc/tmp/${NAME}.input + OUTPUT=~/.dmc/tmp/${NAME}.output + + if [ ${SSL} = 1 ]; then + NETCMD="openssl s_client -host $HOST -port $POST" + else + NETCMD="nc $HOST $PORT" + fi + + echo "Starting $NAME account daemon..." + + rm -f ${INPUT} + mkfifo ${INPUT} +# echo login ${USER} ${PASS} > ${INPUT} + (while : ; do cat ${INPUT} ; done) | \ + ./dmc-${PROTOCOL} $FIFO 2> ${OUTPUT} | $NETCMD > $FIFO + rm -f ${INPUT} +} + +function start_account_daemons { + i=0 + for a in ~/.dmc/acc/* ; do + ( source $a ; acc_daemon ) & + i=$(($i+1)) + done + if [ "$i" = 0 ]; then + echo "No accounts defined in ~/.dmc/acc" + exit 1 + fi +} + +function print_account_template { + echo "NAME='test'" + echo "SSL=0" + echo "PROTOCOL='pop3,imap4'" + echo "HOST=serverhost.com" + echo "PORT=110" + echo "USER='username'" + echo "PASS='password'" +} + +case "$1" in +"-d"|"--start") + start_account_daemons + ;; +"-k"|"--stop") + for a in ~/.dmc/tmp/*.input ; do + echo $a + echo exit > $a + rm -f ~/.dmc/tmp/$a + done + ;; +"-e"|"--edit") + if [ -n "$2" ]; then + if [ -n "`cat ~/.dmc/acc/$2`" ]; then + print_account_template "$2" > ~/.dmc/acc/$2 + fi + vim ~/.dmc/acc/$2 + # Remove account if empty + if [ -z "`cat ~/.dmc/acc/$2`" ]; then + rm ~/.dmc/acc/$2 + fi + else + echo "Usage: dmc -e [accountname]" + fi + ;; +"-a"|"--addr") + if [ -n "$2" ]; then + grep -e "$2" ~/.dmc/addrbook + else + ${EDITOR} ~/.dmc/addrbook + fi + ;; +"-v"|"--version") + echo "dmc v${VERSION} ${COPYRIGHT}" + ;; +"--help"|"-h"|*) + echo "Usage: dmc [-e acc] [-a addr] [-hvdk]" + ;; +esac + +exit 0 diff --git a/dmc.1 b/dmc.1 @@ -0,0 +1 @@ +TODO diff --git a/doc/random b/doc/random @@ -0,0 +1,51 @@ +IMAP handling: +-------------- + Usage: dmc-imap [options] [host] [port] < commands > output + dmc-imap -a plain -d ~/mail [host] [port] + + options: + -a : auth method + -d : base user mail directory + + commands: + cd [folder] + # SELECT "folder" + 1003 [20:47:15] IMAP4> 51 SELECT "Sent Messages" + 1004 [20:47:15] IMAP4< * FLAGS (\Answered \Flagged \Deleted \Seen \Draft $Forwarded) + 1005 [20:47:15] IMAP4< * OK [PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft $Forwarded \*)] Flags permitted. + 1006 [20:47:15] IMAP4< * 340 EXISTS + 1007 [20:47:15] IMAP4< * 2 RECENT + 1008 [20:47:15] IMAP4< * OK [UIDVALIDITY 1230118148] UIDs valid + 1009 [20:47:15] IMAP4< * OK [UIDNEXT 341] Predicted next UID + 1010 [20:47:15] IMAP4< 51 OK [READ-WRITE] Select completed. + + st : show status + 2508 [20:48:11] IMAP4> 60 STATUS "Spam.learn-ham" (MESSAGES UIDNEXT UIDVALIDITY UNSEEN) + 2509 [20:48:12] IMAP4< * STATUS "Spam.learn-ham" (MESSAGES 0 UIDNEXT 1 UIDVALIDITY 1211795420 UNSEEN 0) + 2510 [20:48:12] IMAP4< 60 OK Status completed. + + ls [num] : list num mails (can be used to check for new mail) + cp = copy a mail from one folder to other + mv = copy+remove + rm = remove mail + lt = list folder tree + +LOGIN + Example: C: a001 LOGIN SMITH SESAME + S: a001 OK LOGIN completed +SELECT + Example: C: A142 SELECT INBOX + S: * 172 EXISTS + S: * 1 RECENT + S: * OK [UNSEEN 12] Message 12 is first unseen + S: * OK [UIDVALIDITY 3857529045] UIDs valid + S: * OK [UIDNEXT 4392] Predicted next UID + S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft) + S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited + S: A142 OK [READ-WRITE] SELECT completed +CREATE + Example: C: A003 CREATE owatagusiam/ + S: A003 OK CREATE completed + C: A004 CREATE owatagusiam/blurdybloop + S: A004 OK CREATE completed + diff --git a/doc/wipmail.txt b/doc/wipmail.txt @@ -0,0 +1,110 @@ +markus schnalke wrote: +> [2009-10-06 16:26] pancake <pancake@youterm.com> +> +>> PD: Actually I have not found a more fast, usable and simplest mail client +>> than the one shipped with iphone-os. And no, fetchmail,mutt,claws,telnet +>> are not decent solutions. Should we open another thread to create a suckless +>> mail client? +>> +> +> What do you mean with ``mail client''? MTA, MUA, MDA, or all of them in one? +> +A solution that manages MTA, MUA, MDA and MDMA plus LSD in a simple +way. + +This is: + - Keep a partial local cache of the mails (only last 50?) + - imap support server search, so why i have to mirror the folders +with 53200 mails? + - Only sync selected folders automatically or every N minutes + - Attachments should be only retrieved in a second stage (on slow +connections + is really useful) + +Client must provide a simple tree way to walk on folders (filesystem?) +every time a mail is fetched a file is created and it is touched with +the specified timestamp. + +I already wrote a patch for msmtp that checks for the MX entry for a +domain to +automatically specify the remote SMTP server, so no need to configure +any smtp +server for sending mails. I find this solution much simpler for most +situations (unless +you are on a restricted network that only allows you to connect to your +local smtp) + +So, what I see here is a simple application that manages files in +directories and allows to create formatted files (using a template) on +some directories using $EDITOR, +a command to check files in Outbox to push them to remote servers and commit +them into the Sent directory. + +The basic imap operations can be easily mapped as filesystem ones: + - list, copy, move, remove + +Just having a simple application to manage pop3/smtp with those minimal +operations +and writing a simple frontend to edit files on certain directories based +on templates. + +Stuff like gpg, html2text (or text2html for those who wants to raise +hate on mailing +lists), filters to format a mail into a 'reply' format prefixing lines +with '>' ... are just +pre and post-hooks when calling the $EDITOR or $PAGER. + +The only missing thing I see in this model is the part of attached +files. This can be +solved by having a directory with the same filename of the mail plus +.files and have +an application to serialize mail+attachments into a single text stream +before sending +it to the smtp (maybe using msmtp) can be ideal. + +To setup accounts I can think on a single entrypoint with simple format +that configures +the rest of applications to work with. + +Multiple accounts should be managed by this approach. Marking emails as +read/... +can be just a sed script changing a header. + +I have never understood why there is no decent mail implementation like +the one +explained above. The only problematic to implement such thing is the +lack of decent +smtp/pop/imap clients. I think that ssl support can be done by local +openssl bouncers. + +Another *important* thing is that the SSL stuff must be checked, so in +this way you +can setup any kind of secure connection without having to reconfigure +your mail +client. This is: connecting to localhost:110 to bounce the socket to an +VPN or an DNSTX +network (or TOR, etc...), the client will just know nothing about the +underlying network, +and the bouncer app will be the one to ensure that the connection is not +broken. + +Network *must* be an async dependency for a mail client, so I hate when +the client gets +locked because of a network cut or slowdown, it is just something that +cannot be understood +nowadays. + +By having all this simple setup done (in a single package, please, i +dont want to configure +3 or 4 programs to get my email working) i can imagine a lot of +automatizations in scripts +to autoreply emails, filter spam, etc.. And the GUI is actually a +filesystem. + +Email syncing is not only a thing of pop3/imap, we can also think on +using ssh or fuse to +access/sync to our remote mailboxes or maildirs. + +--pancake + + diff --git a/doc/wipmail2.txt b/doc/wipmail2.txt @@ -0,0 +1,70 @@ + +I've managed to build tinymail..but a gobject framework of 16MB size is +not exactly +minimal, tiny or suckless in any way. + +The repository comes with no commandline or non-gtk dependent example. + +I still think that it is possible to implement a smtp/pop3/imap protocol +handler in less +than 1000LOC, all protocols are text based and by just defining a few +functions for +handling timeouts, responses and so on shouldnt be that hard. + +6 years ago I wrote a mail daemon (SMTP) in about 500LOC able to manage +mbox, +several auth methods and mutliple connections at the same time. + +fetchmail has lot of unnecessary features and lacks many useful +functionalities. + +msmtp is cool, but I always find it unnecesarily complex for the things +it has to do. For +example, the network layer if wrapped by a bouncer can permit to keep +connections +alive, add encription, tunels and many other funny stuff. + +What I'm proposing is a simple setup with wrappers for +sendmail,msmtp,whatever that +can be exchanged by just changing a hook script. + +About attaching files I have some minimal base64 algorithms, so it +should be that hard +to make it work in stream like: + + $ cat mail | add-attachments mail.d/* | msmtp mail@to.com + +And the same for extracting the attachments. + +I dont really think this is a loss of time (yeah, you can hate me), but +I hate to be forced +to use bloatware everywhere. + +I also use tinymail on the n810 because is the one that comes by default +in the last +firmwares because is just much better than the monolitic approach from +Nokia, but +having 16MB++ of memory slurped by a mail library on an embedded device +is imho +not a good thing. But I understand that having dbus to avoid doing +innecessary stuff +when the device is offline and earn battery is a good thing, but at +least I would prefer +to have my own minimal stack of mail management. + + +--pancake + +Kurt H Maier wrote: +> Check out tinymail[1]. This guy took a pretty cerebral approach to +> developing his MUA back-end library. I've used it in the form of +> Modest[2] on my Nokia n810. +> +> Personally, I'd hate to see any more dev hours wasted on garbage like +> imap or pop3. ssh/rsyncing maildir to form a 'local copy,' then +> 'commiting' changes back seems much saner to me. +> +> [1] - http://tinymail.org/ +> [2] - http://modest.garage.maemo.org/ +> +> diff --git a/imap4.c b/imap4.c @@ -0,0 +1,107 @@ +/* dmc :: Copyleft -- pancake (at) nopcode (dot) org */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +static char word[1024]; +static int ctr = 1; + +static char *getword() { + fscanf(stdin, "%127s", word); + if (feof(stdin)) + *word = '\0'; + return word; +} + +static int waitreply() { + char *str; + int ret = -1; + fgets(word, sizeof(word), stdin); + if (atoi(word) != ctr-1) + fprintf(stderr, "Invalid sequence number received\n"); + if ( (str = strchr(word, ' ')) ) { + if (!memcmp(str+1, "OK", 3)) + ret = 1; + else if (!memcmp(str+1, "NO", 4)) + ret = 0; + } + return ret; // 1 if true, 0 if false +} + +#if 0 +LIST - list all folders +LSUB - list all subscribed folders +SUBSCRIBE - subcribe a folder +CHECK - ??? +CLOSE - commit the delete stuff (maybe must be done after rm) +EXPUNGE - permanent remove of deltec +SEARCH - ... +RECENT - show the number of recent messages +#endif +static int doword(char *word) { + int ret = 1; + if (*word == '\0' || !strcmp(word, "exit")) { + printf("%d LOGOUT\n", ctr++); + waitreply(); + ret = 0; + } else + if (!strcmp(word, "help") || !strcmp(word, "?")) { + fprintf(stderr, "Use: ls lsdir cat head rm rmdir login exit mvdir\n"); + } else + if (!strcmp(word, "ls")) { +// TODO: + printf("LIST\n"); + waitreply(); + } else + if (!strcmp(word, "cd")) { + printf("%d SELECT %s\n", ctr++, getword()); + waitreply(); + } else + if (!strcmp(word, "search")) { + printf("%d SEARCH TEXT \"%s\"\n", ctr++, getword()); + waitreply(); + } else + if (!strcmp(word, "lsdir")) { + printf("%d LIST \"\" *\n", ctr++); + waitreply(); + } else + if (!strcmp(word, "cat")) { + printf("%d FETCH %d ALL\n", + ctr++, atoi(getword())); + waitreply(); + } else + if (!strcmp(word, "head")) { + printf("%d FETCH %d body[header]\n", + ctr++, atoi(getword())); + waitreply(); + } else + if (!strcmp(word, "mvdir")) { + printf("%d RENAME %s %s\n", + ctr++, getword(), getword()); + } else + if (!strcmp(word, "rm")) { +// TODO: + printf("DELE %d\n", atoi(getword())); + waitreply(); + } else + if (!strcmp(word, "rmdir")) { + printf("%d DELETE %d\n", + ctr++, atoi(getword())); + waitreply(); + } else + if (!strcmp(word, "login")) { + printf("%d LOGIN %s %s\n", + ctr++, getword(), getword()); + waitreply(); + } else { + printf("%d NOOP\n", ctr++); + waitreply(); + } + return ret; +} + +int main() { + while(doword(getword())); + return 0; +} diff --git a/pop3.c b/pop3.c @@ -0,0 +1,139 @@ +/* dmc :: Copyleft -- pancake (at) nopcode (dot) org */ + +#include <stdio.h> +#include <string.h> +#include <signal.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <poll.h> + + +static char *cmd = NULL; +static char word[1024]; +static char *fifo; +static int ff; + +/* XXX : Use of stdin FILE* fails when using fifo files */ +static char *getword() { + fscanf(stdin, "%255s", word); + if (feof(stdin)) + *word = '\0'; + return word; +} + +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 int waitreply(int lock) { + char *ch, *str = word; + int ret, reply = -1; + fflush(stdout); + while(lock || ready()) { + lock = 0; + ret = read(ff, word, 512); + if (ret<1) + break; + word[ret] = 0; + if (reply==-1) { + ch = strchr(str, '\r'); + if (!ch) ch = strchr(str, '\n'); + if (ch) { + if (!memcmp(word, "+OK", 3)) + reply = 1; + else + if (!memcmp(word, "-ERR", 4)) + reply = 0; + *ch = 0; + fprintf(stderr, "%s %d \"%s\"\n", cmd, ret, str); + str = ch+((ch[1]=='\n')?2:1); + } + } + // TODO: \r \n issues + ch = strstr(str, "\r\n."); + if (ch) + *ch = '\0'; + fprintf(stderr, "%s\n", str); + } + fflush(stderr); + write(2, "\x00", 1); // end of output + return reply; +} + +static int doword(char *word) { + int ret = 1; + free (cmd); + cmd = strdup(word); + //if (*word == '\0' || !strcmp(word, "exit")) { + if (*word == '\0') { + /* Do nothing */ + } else + if (!strcmp(word, "exit")) { + printf("QUIT\n"); + waitreply(1); + ret = 0; + } else + if (!strcmp(word, "help") || !strcmp(word, "?")) { + fprintf(stderr, "Use: ls cat head rm login exit\n"); + } else + if (!strcmp(word, "ls")) { + printf("LIST\n"); + waitreply(1); + } else + if (!strcmp(word, "cat")) { + printf("RETR %d\n", atoi(getword())); + waitreply(1); + } else + if (!strcmp(word, "head")) { + printf("TOP %d\n", atoi(getword())); + waitreply(1); + } else + if (!strcmp(word, "rm")) { + printf("DELE %d\n", atoi(getword())); + waitreply(1); + } else + if (!strcmp(word, "login")) { + printf("USER %s\n", getword()); + waitreply(1); + printf("PASS %s\n", getword()); + waitreply(1); + } else printf("NOOP\n"); + return ret; +} + +static void parseoutput(void) { + while(!feof(stdin)) { + sleep(1); + printf("TODO\n"); + } +} + +static void cleanup(int foo) { + close(ff); + unlink(fifo); + exit(0); +} + +int main(int argc, char **argv) { + 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; +} diff --git a/smtp.c b/smtp.c @@ -0,0 +1,3 @@ +int main() { + return 0; +} diff --git a/src/Makefile b/src/Makefile @@ -1,32 +0,0 @@ -CC?=gcc -PREFIX?=/usr -CFLAGS?=-Wall - -all: dmc-smtp dmc-pop3 dmc-imap4 - -dmc-smtp: smtp.o - ${CC} ${LDFLAGS} smtp.o -o dmc-smtp - -dmc-pop3: pop3.o - ${CC} ${LDFLAGS} pop3.o -o dmc-pop3 - -dmc-imap4: imap4.o - ${CC} ${LDFLAGS} imap4.o -o dmc-imap4 - -install: - cp -f dmc ${PREFIX}/bin - cp -f dmc-smtp ${PREFIX}/bin - cp -f dmc-pop3 ${PREFIX}/bin - cp -f dmc-imap4 ${PREFIX}/bin - -uninstall: - rm -f ${PREFIX}/bin/dmc - rm -f ${PREFIX}/bin/dmc-smtp - rm -f ${PREFIX}/bin/dmc-pop3 - rm -f ${PREFIX}/bin/dmc-imap4 - -clean: - rm -f dmc-pop3 dmc-imap4 dmc-smtp *.o - -loc: - sloccount . diff --git a/src/dmc b/src/dmc @@ -1,97 +0,0 @@ -#!/bin/sh -# -# Dynamic Mail Client -# - -VERSION="0.1" -COPYRIGHT="Copyleft -- pancake@nopcode.org" - -[ -n "${EDITOR}" ] && EDITOR=vim -mkdir -p ~/.dmc/mail -mkdir -p ~/.dmc/tmp -mkdir -p ~/.dmc/acc - -function acc_daemon { - FIFO=~/.dmc/tmp/${NAME}.fifo - INPUT=~/.dmc/tmp/${NAME}.input - OUTPUT=~/.dmc/tmp/${NAME}.output - - if [ ${SSL} = 1 ]; then - NETCMD="openssl s_client -host $HOST -port $POST" - else - NETCMD="nc $HOST $PORT" - fi - - echo "Starting $NAME account daemon..." - - rm -f ${INPUT} - mkfifo ${INPUT} -# echo login ${USER} ${PASS} > ${INPUT} - (while : ; do cat ${INPUT} ; done) | \ - ./dmc-${PROTOCOL} $FIFO 2> ${OUTPUT} | $NETCMD > $FIFO - rm -f ${INPUT} -} - -function start_account_daemons { - i=0 - for a in ~/.dmc/acc/* ; do - ( source $a ; acc_daemon ) & - i=$(($i+1)) - done - if [ "$i" = 0 ]; then - echo "No accounts defined in ~/.dmc/acc" - exit 1 - fi -} - -function print_account_template { - echo "NAME='test'" - echo "SSL=0" - echo "PROTOCOL='pop3,imap4'" - echo "HOST=serverhost.com" - echo "PORT=110" - echo "USER='username'" - echo "PASS='password'" -} - -case "$1" in -"-d"|"--start") - start_account_daemons - ;; -"-k"|"--stop") - for a in ~/.dmc/tmp/*.input ; do - echo $a - echo exit > $a - rm -f ~/.dmc/tmp/$a - done - ;; -"-e"|"--edit") - if [ -n "$2" ]; then - if [ -n "`cat ~/.dmc/acc/$2`" ]; then - print_account_template "$2" > ~/.dmc/acc/$2 - fi - vim ~/.dmc/acc/$2 - # Remove account if empty - if [ -z "`cat ~/.dmc/acc/$2`" ]; then - rm ~/.dmc/acc/$2 - fi - else - echo "Usage: dmc -e [accountname]" - fi - ;; -"-a"|"--addr") - if [ -n "$2" ]; then - grep -e "$2" ~/.dmc/addrbook - else - ${EDITOR} ~/.dmc/addrbook - fi - ;; -"-v"|"--version") - echo "dmc v${VERSION} ${COPYRIGHT}" - ;; -"--help"|"-h"|*) - echo "Usage: dmc [-e acc] [-a addr] [-hvdk]" - ;; -esac - -exit 0 diff --git a/src/imap4.c b/src/imap4.c @@ -1,107 +0,0 @@ -/* dmc :: Copyleft -- pancake (at) nopcode (dot) org */ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> - -static char word[1024]; -static int ctr = 1; - -static char *getword() { - fscanf(stdin, "%127s", word); - if (feof(stdin)) - *word = '\0'; - return word; -} - -static int waitreply() { - char *str; - int ret = -1; - fgets(word, sizeof(word), stdin); - if (atoi(word) != ctr-1) - fprintf(stderr, "Invalid sequence number received\n"); - if ( (str = strchr(word, ' ')) ) { - if (!memcmp(str+1, "OK", 3)) - ret = 1; - else if (!memcmp(str+1, "NO", 4)) - ret = 0; - } - return ret; // 1 if true, 0 if false -} - -#if 0 -LIST - list all folders -LSUB - list all subscribed folders -SUBSCRIBE - subcribe a folder -CHECK - ??? -CLOSE - commit the delete stuff (maybe must be done after rm) -EXPUNGE - permanent remove of deltec -SEARCH - ... -RECENT - show the number of recent messages -#endif -static int doword(char *word) { - int ret = 1; - if (*word == '\0' || !strcmp(word, "exit")) { - printf("%d LOGOUT\n", ctr++); - waitreply(); - ret = 0; - } else - if (!strcmp(word, "help") || !strcmp(word, "?")) { - fprintf(stderr, "Use: ls lsdir cat head rm rmdir login exit mvdir\n"); - } else - if (!strcmp(word, "ls")) { -// TODO: - printf("LIST\n"); - waitreply(); - } else - if (!strcmp(word, "cd")) { - printf("%d SELECT %s\n", ctr++, getword()); - waitreply(); - } else - if (!strcmp(word, "search")) { - printf("%d SEARCH TEXT \"%s\"\n", ctr++, getword()); - waitreply(); - } else - if (!strcmp(word, "lsdir")) { - printf("%d LIST \"\" *\n", ctr++); - waitreply(); - } else - if (!strcmp(word, "cat")) { - printf("%d FETCH %d ALL\n", - ctr++, atoi(getword())); - waitreply(); - } else - if (!strcmp(word, "head")) { - printf("%d FETCH %d body[header]\n", - ctr++, atoi(getword())); - waitreply(); - } else - if (!strcmp(word, "mvdir")) { - printf("%d RENAME %s %s\n", - ctr++, getword(), getword()); - } else - if (!strcmp(word, "rm")) { -// TODO: - printf("DELE %d\n", atoi(getword())); - waitreply(); - } else - if (!strcmp(word, "rmdir")) { - printf("%d DELETE %d\n", - ctr++, atoi(getword())); - waitreply(); - } else - if (!strcmp(word, "login")) { - printf("%d LOGIN %s %s\n", - ctr++, getword(), getword()); - waitreply(); - } else { - printf("%d NOOP\n", ctr++); - waitreply(); - } - return ret; -} - -int main() { - while(doword(getword())); - return 0; -} diff --git a/src/pop3.c b/src/pop3.c @@ -1,139 +0,0 @@ -/* dmc :: Copyleft -- pancake (at) nopcode (dot) org */ - -#include <stdio.h> -#include <string.h> -#include <signal.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <poll.h> - - -static char *cmd = NULL; -static char word[1024]; -static char *fifo; -static int ff; - -/* XXX : Use of stdin FILE* fails when using fifo files */ -static char *getword() { - fscanf(stdin, "%255s", word); - if (feof(stdin)) - *word = '\0'; - return word; -} - -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 int waitreply(int lock) { - char *ch, *str = word; - int ret, reply = -1; - fflush(stdout); - while(lock || ready()) { - lock = 0; - ret = read(ff, word, 512); - if (ret<1) - break; - word[ret] = 0; - if (reply==-1) { - ch = strchr(str, '\r'); - if (!ch) ch = strchr(str, '\n'); - if (ch) { - if (!memcmp(word, "+OK", 3)) - reply = 1; - else - if (!memcmp(word, "-ERR", 4)) - reply = 0; - *ch = 0; - fprintf(stderr, "%s %d \"%s\"\n", cmd, ret, str); - str = ch+((ch[1]=='\n')?2:1); - } - } - // TODO: \r \n issues - ch = strstr(str, "\r\n."); - if (ch) - *ch = '\0'; - fprintf(stderr, "%s\n", str); - } - fflush(stderr); - write(2, "\x00", 1); // end of output - return reply; -} - -static int doword(char *word) { - int ret = 1; - free (cmd); - cmd = strdup(word); - //if (*word == '\0' || !strcmp(word, "exit")) { - if (*word == '\0') { - /* Do nothing */ - } else - if (!strcmp(word, "exit")) { - printf("QUIT\n"); - waitreply(1); - ret = 0; - } else - if (!strcmp(word, "help") || !strcmp(word, "?")) { - fprintf(stderr, "Use: ls cat head rm login exit\n"); - } else - if (!strcmp(word, "ls")) { - printf("LIST\n"); - waitreply(1); - } else - if (!strcmp(word, "cat")) { - printf("RETR %d\n", atoi(getword())); - waitreply(1); - } else - if (!strcmp(word, "head")) { - printf("TOP %d\n", atoi(getword())); - waitreply(1); - } else - if (!strcmp(word, "rm")) { - printf("DELE %d\n", atoi(getword())); - waitreply(1); - } else - if (!strcmp(word, "login")) { - printf("USER %s\n", getword()); - waitreply(1); - printf("PASS %s\n", getword()); - waitreply(1); - } else printf("NOOP\n"); - return ret; -} - -static void parseoutput(void) { - while(!feof(stdin)) { - sleep(1); - printf("TODO\n"); - } -} - -static void cleanup(int foo) { - close(ff); - unlink(fifo); - exit(0); -} - -int main(int argc, char **argv) { - 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; -} diff --git a/src/smtp.c b/src/smtp.c @@ -1,3 +0,0 @@ -int main() { - return 0; -}