dmc

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

commit 43eaf431363a563976bc93d3b69df5f80cbac5ba
parent 408e8287b667c34daae6513a0815b649118ff65a
Author: pancake <nopcode.org>
Date:   Mon, 10 May 2010 00:16:18 +0200

* Implement -r and -f to reply and forward mails
* [FWD|REG]|[MSG|SUB] in config.def.h to configure messages
* evalstr() filters subject and reply/forward message
* Commands are now stored in global DmcQuery reply
* Create all basic home directories in -e
Diffstat:
TODO | 8+++-----
config.def.h | 4++++
dmc.c | 223+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
3 files changed, 180 insertions(+), 55 deletions(-)

diff --git a/TODO b/TODO @@ -1,11 +1,9 @@ TODO ---- +* PULL METHOD: +* lsd ! cd - ; ls ! get 1 +--- * Make it more fail-fast (use exit, instead of free) -* how to reply a mail? - - dmc -r [mail] [addr] - -> runs dmc-filter -b < mail | sed -e 's,^,> ,' -* how to forward a mail? - - dmc -f [mail] [addr] * Create a mail with attachments (dmc -m addr subject file1 file2 file3 ..) * Attach file to given mail (not last one) * Define a list of 'subscribed' folders for IMAP ~/.dmc/box/.folders ? diff --git a/config.def.h b/config.def.h @@ -3,3 +3,7 @@ #define DIRPERM 0750 #define EDITOR "vim" #define MAXACC 16 /* maximum number of accounts */ +#define FWDMSG "Begin forwarded message:\n" +#define REPMSG "On {Date: }, {From: } wrote:\n" +#define FWDSUB "Fwd: " +#define REPSUB "Re: " diff --git a/dmc.c b/dmc.c @@ -18,10 +18,19 @@ static int dmc_in[2], dmc_out[2], dmc_err[2]; static int dmc_pid = -1; static fd_set rfds, wfds; +typedef struct { + char *out; + char *err; + int errlen; +} DmcQuery; + +static DmcQuery reply; + static void dmcstop(); static int dmcsend(const char *file); static int fexist(const char *path); +#if 0 static char *dmcnamegen(const char *file) { // return filename from mail // Name is YYYYMMDDhhmm## -- name sort by date @@ -31,11 +40,39 @@ static char *dmcnamegen(const char *file) { return NULL; } +static int dmcstore() { + // TODO + return 0; +} +#endif + +static const char *dmcalias(const char *filter) { + static char line[64]; + FILE *fd = fopen (DMCDIR"/addrbook", "r"); + if (fd) { + for (;;) { + fgets (line, sizeof (line), fd); + if (feof (fd)) + break; + if (strstr (line, filter)) { + line[strlen(line)-1] = 0; + return line; + } + } + fclose (fd); + } + return filter; +} + static const char *dmcmailpath(const char *name) { static char path[256]; /* check ./%s */ if (fexist (name)) return name; + /* check DMCDIR/box/$acc/in/%s.eml */ + snprintf (path, sizeof (path), DMCDIR"/box/%s/in/%s.eml", defacc, name); + if (fexist (path)) + return path; /* check DMCDIR/box/$acc/in/%s */ snprintf (path, sizeof (path), DMCDIR"/box/%s/in/%s", defacc, name); if (fexist (path)) @@ -65,6 +102,7 @@ static void dmcinit() { defacc = acc[0]; signal (SIGINT, dmcstop); atexit (dmcstop); + reply.out = reply.err = NULL; } static char *cfgget(const char *key) { @@ -189,14 +227,19 @@ static void dmcstop() { } } -static char *dmccmd(const char *cmd, char *err, int errlen) { - static char buf[4096]; +static int dmccmd(const char *cmd) { + static char buf[128]; int ret, nfd; if (dmc_pid == -1) { printf ("Use 'on' or '?'\n"); - return NULL; + return 0; } + free (reply.out); + reply.out = NULL; + free (reply.err); + reply.err = NULL; + reply.errlen = 0; for (;;) { FD_ZERO (&rfds); FD_ZERO (&wfds); @@ -210,7 +253,8 @@ static char *dmccmd(const char *cmd, char *err, int errlen) { ret = read (dmc_out[0], buf, sizeof (buf)-1); if (ret>0) { buf[ret-1] = 0; - printf ("-(out)-> (%s)\n", buf); + reply.out = strdup (buf); // XXX + //printf ("-(out)-> (%s)\n", buf); break; } } else @@ -218,7 +262,10 @@ static char *dmccmd(const char *cmd, char *err, int errlen) { ret = read (dmc_err[0], buf, sizeof (buf)-1); if (ret>0) { buf[ret-1] = 0; - printf ("-(err)-> (%s)\n", buf); + reply.err = realloc (reply.err, reply.errlen+ret+1); + memcpy (reply.err+reply.errlen, buf, ret); + reply.errlen += ret-1; + //printf ("-(err)-> (%s)\n", buf); } } else if (FD_ISSET (dmc_in[1], &wfds)) { @@ -230,7 +277,7 @@ static char *dmccmd(const char *cmd, char *err, int errlen) { } } } - return buf; + return 1; } static int dmcpull(const char *name) { @@ -253,8 +300,10 @@ static void dmcpush(const char *name) { printf ("%s: ", file); fflush (stdout); if (dmcsend (file)) { - // TODO: remove .d - unlink (file); + snprintf (path, sizeof (path), + "mv %s* "DMCDIR"/box/%s/sent", + file, defacc); + system (path); // do not use system() } } } @@ -329,8 +378,7 @@ static int dmcsend(const char *file) { } static int dmcline(const char *line) { - char err[128], cmd[128]; - char *ptr = strchr (line, ' '); + char cmd[128]; if (!strcmp (line, "?")) { printf ("Usage: on off push pull exit ls cat ..\n"); } else @@ -338,13 +386,15 @@ static int dmcline(const char *line) { char *user = cfgget ("USER="); char *pass = cfgget ("PASS="); snprintf (cmd, sizeof (cmd), "login %s %s\n", user, pass); - ptr = dmccmd (cmd, err, sizeof (err)); + if (!dmccmd (cmd)) + printf ("Error.\n"); free (user); free (pass); } else if (!strcmp (line, "on")) { dmcstart (acc[0]); - ptr = dmccmd (NULL, err, sizeof (err)); + if (!dmccmd (NULL)) + printf ("Error.\n"); } else if (!strcmp (line, "off")) { dmcstop (); @@ -362,11 +412,9 @@ static int dmcline(const char *line) { return 0; } else { /* bypass to child */ - ptr = dmccmd (line, err, sizeof (err)); - if (ptr) { - printf ("%s\n", ptr); - fprintf (stderr, "%s\n", err); - //free (ptr); + if (dmccmd (line)) { + printf ("-(out)-> %s\n", reply.out); + printf ("-(err)-> %s\n", reply.err); } else fprintf (stderr, "## No reply\n"); } return 1; @@ -374,25 +422,23 @@ static int dmcline(const char *line) { static int usage(const char *argv0, int lon) { fprintf (stderr, "Usage: %s [-hv] [-c [cmd] [-s file] [-e acc] [-A file ..]\n" - "\t [-a addr] [-m [A|S A]] [-l [box]]\n", argv0); - if (lon) { - fprintf (stderr, - " -m [A [S]] create mail (Address, Subject)\n" - " -c [cmd] command shell\n" - " -e [acc] list/edit/set default accounts\n" - " -a [addr] grep in addressbook\n" - " -A [file .] attach files to ~/.dmc/mail.last done by 'dmc -m'\n" - " -l [box] list mails in specified box of def account\n" - " -s [file] send mail\n" - //" -f [file] forward mail\n" - //" -r [file] reply mail\n" - " -v show version\n" - ""); - } + "\t [-a addr] [-m [a [s [..]] [-f m a] [-r m a] [-l [box]]\n", argv0); + if (lon) fprintf (stderr, + " -m [a [s]..] create mail [addr [subj [file1 file2 ..]]]\n" + " -c [cmd] command shell\n" + " -e [acc] list/edit/set default accounts\n" + " -a [addr] grep in addressbook\n" + " -A [file .] attach files to ~/.dmc/mail.last done by 'dmc -m'\n" + " -l [box] list mails in specified box of def account\n" + " -s [file] send mail\n" + " -f m [addr] forward mail to addr\n" + " -r m [addr] reply mail to addr\n" + " -v show version\n" + ""); return 0; } -static int dmcmail(const char *addr, const char *subj) { +static int dmcmail(const char *addr, const char *subj, const char *slurp, const char *slurptitle) { const char *from = cfgget("MAIL="); char file[128], line[128]; int fd; @@ -405,6 +451,23 @@ static int dmcmail(const char *addr, const char *subj) { "To: %s\n" "Subject: %s\n\n\n", from, addr, subj); write (fd, line, strlen (line)); + if (slurp) { + FILE *sfd = fopen (slurp, "r"); + if (sfd) { + int body = 0; + write (fd, "\n\n", 2); + if (slurptitle) + write (fd, slurptitle, strlen (slurptitle)); + for (;;) { + fgets (line, sizeof (line), sfd); + if (feof (sfd)) break; + if (body) { + write (fd, "> ", 2); + write (fd, line, strlen (line)); + } else if (strlen (line)<4) body = 1; + } + } + } close (fd); snprintf (line, sizeof (line), EDITOR" %s", file); system (line); @@ -430,6 +493,58 @@ static void dmcattach(const char *file) { } else fprintf (stderr, "Cannot attach '%s'\n", file); } +static char *evalstr(const char *mail, const char *str) { + int outi = 0; + char *out, *tmp; + const char *ptr = str; + out = malloc (1024); // XXX overflow + while (*ptr) { + if (*ptr == '{') { + int dsti = 0; + char dst[1024]; + ptr++; + while (*ptr && *ptr != '}' && dsti<sizeof(dst)-1) { + dst[dsti++] = *ptr; + ptr++; + } + dst[dsti] = 0; + tmp = gethdr ("/", mail, dst); + if (tmp) { + strcpy (out+outi, tmp); + outi += strlen (tmp); + free (tmp); + } + ptr++; + continue; + } + out[outi++] = *ptr; + ptr++; + } + out[outi] = 0; + return out; +} + +static void dmcfwd(const char *file, const char *addr, const char *msg, const char *sub) { + if (file) { + char *m, *subj, *msub = gethdr ("/", file, "Subject: "); + if (msub) { + char *s = evalstr (file, sub); + subj = malloc (strlen (msub) + strlen (s) + 2); + strcpy (subj, s); + strcat (subj, msub); + free (s); + } else { + subj = strdup (sub); + } + if (addr && *addr) + addr = dmcalias (addr); + m = evalstr (file, msg); + dmcmail (addr, subj, file, m); + free (m); + free (subj); + } else fprintf (stderr, "Mail not found.\n"); +} + int main(int argc, char **argv) { char file[128], line[128]; struct dirent *de; @@ -487,13 +602,17 @@ int main(int argc, char **argv) { break; case 'm': { - char *addr = ""; - char *subj = ""; + const char *addr = ""; + const char *subj = ""; if (argc>2) addr = argv[2]; if (argc>3) subj = argv[3]; - dmcmail (addr, subj); + if (addr && !strchr (addr, '@')) + addr = dmcalias (addr); + if (dmcmail (addr, subj, NULL, NULL)) + for (i=4; argv[i]; i++) + dmcattach (argv[i]); } break; case 'e': @@ -532,6 +651,14 @@ int main(int argc, char **argv) { printf ("Default account has changed.\n"); unlink (DMCDIR"/acc.default"); symlink (file, DMCDIR"/acc.default"); + snprintf (line, sizeof (line), DMCDIR"/box/%s", argv[2]); + mkdir (line, DIRPERM); + snprintf (line, sizeof (line), DMCDIR"/box/%s/out", argv[2]); + mkdir (line, DIRPERM); + snprintf (line, sizeof (line), DMCDIR"/box/%s/in", argv[2]); + mkdir (line, DIRPERM); + snprintf (line, sizeof (line), DMCDIR"/box/%s/sent", argv[2]); + mkdir (line, DIRPERM); } } break; @@ -540,19 +667,9 @@ int main(int argc, char **argv) { snprintf (line, sizeof (line), EDITOR" '"DMCDIR"/addrbook'"); system (line); } else { - FILE *fd = fopen (DMCDIR"/addrbook", "r"); - if (fd) { - for (;;) { - fgets (line, sizeof (line), fd); - if (feof (fd)) - break; - for (i=2; i<argc; i++) { - if (strstr (line, argv[i])) - printf ("%s", line); - } - } - fclose (fd); - } + const char *mail = dmcalias (argv[2]); + if (mail) + puts (mail); } break; case 'c': @@ -567,11 +684,17 @@ int main(int argc, char **argv) { } while (dmcline (line)); } else { strcpy (prompt, ""); - for(i=2; i<argc; i++) + for (i=2; i<argc; i++) dmcline (argv[i]); } dmcstop (); break; + case 'r': // reply + dmcfwd (dmcmailpath (argv[2]), argc>3?argv[3]:"", REPMSG, REPSUB); + break; + case 'f': // forward + dmcfwd (dmcmailpath (argv[2]), argc>3?argv[3]:"", FWDMSG, FWDSUB); + break; default: return usage (argv[0], 1); }