commit 319c99b3d1305c69ce8e0bb09815a068877d38da
parent fdeff1b6e7b09bedb1f87326fc70a90716503980
Author: pancake <nopcode.org>
Date: Tue, 4 May 2010 01:56:45 +0200
* Mostly full replacement of dmc in C
- old dmc is named dmc.sh (will be removed)
- pop3 is fully working and mostly usable to
be automatized for 'pull'
* dmc-pack pack mails when no arguments given)
Diffstat:
Makefile | | | 13 | +++++++++---- |
config.def.h | | | 4 | ++++ |
dmc | | | 321 | ------------------------------------------------------------------------------- |
dmc-cmd.c | | | 272 | ------------------------------------------------------------------------------- |
dmc.c | | | 527 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
dmc.sh | | | 321 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
pack.c | | | 8 | +++++--- |
7 files changed, 866 insertions(+), 600 deletions(-)
diff --git a/Makefile b/Makefile
@@ -7,13 +7,17 @@ endif
CFLAGS+=-DHAVE_SSL=${HAVE_SSL}
CFLAGS+=-DVERSION=\"${VERSION}\"
+CFLAGS+=-DPREFIX=\"${PREFIX}\"
-BINS=dmc-cmd dmc-mbox dmc-smtp dmc-pop3 dmc-imap4 dmc-pack dmc-filter dmc-mbox
+BINS=dmc dmc-mbox dmc-smtp dmc-pop3 dmc-imap4 dmc-pack dmc-filter dmc-mbox
-all: ${BINS}
+all: config.h ${BINS}
-dmc-cmd: dmc-cmd.o
- ${CC} dmc-cmd.o -o dmc-cmd
+config.h:
+ cp config.def.h config.h
+
+dmc: dmc.o
+ ${CC} dmc.o -o dmc
dmc-smtp: smtp.o
${CC} ${LDFLAGS} smtp.o -o dmc-smtp -lresolv
@@ -41,6 +45,7 @@ install:
chmod +x dmc dmc-tag dmc-mdir
cp -f dmc.1 ${PREFIX}/share/man/man1
cp -f dmc ${PREFIX}/bin
+ cp -f dmc.sh ${PREFIX}/bin
cp -f dmc-tag ${PREFIX}/bin
cp -f dmc-smtp ${PREFIX}/bin
cp -f dmc-pop3 ${PREFIX}/bin
diff --git a/config.def.h b/config.def.h
@@ -0,0 +1,4 @@
+#define VERSION "0.1"
+#define DMCDIR "/home/pancake/.dmc"
+#define DIRPERM 0750
+#define EDITOR "vim"
diff --git a/dmc b/dmc
@@ -1,321 +0,0 @@
-#!/bin/sh
-# dmc - dynamic mail client
-# See LICENSE file for copyright and license details.
-
-VERSION="0.1"
-HELP="Usage: dmc [-hv] [-e acc] [-a addr] [-m addr subj] [-A file] [-s msg] [action]"
-
-[ -z "${EDITOR}" ] && EDITOR=vim
-mkdir -p ~/.dmc/mail
-mkdir -p ~/.dmc/tmp
-mkdir -p ~/.dmc/acc
-[ -e ~/.dmc/acc.default ] && . ~/.dmc/acc.default
-
-chkcfg () {
- if [ -z "${NAME}" ]; then
- echo "No selected mail account. Use 'dmc -e'"
- exit 1
- fi
-}
-
-acc_daemon () {
- chkcfg
- LOCK=~/.dmc/tmp/${NAME}.lock
- INPUT=~/.dmc/tmp/${NAME}.input
- OUTPUT=~/.dmc/tmp/${NAME}.output
-
- echo "Starting $NAME account $PROTOCOL daemon..."
-
- rm -f "${LOCK}" "${INPUT}" "${OUTPUT}"
- mkfifo "${LOCK}" "${INPUT}"
-
- # wait 1 connect message and 1 login message
- (head -n 2 ${LOCK} ; dmc_cmd "login ${USER} ${PASS}" ; dmc_cmd "ls") &
- (while : ; do cat ${INPUT} 2> /dev/null ; done) | \
- dmc-${PROTOCOL} ${HOST} ${PORT} ${SSL} 2> ${OUTPUT} > ${LOCK}
- rm -f "${LOCK}" "${INPUT}" "${OUTPUT}"
-}
-
-dmc_cmd () {
- [ -z "$1" ] && return
- echo "$@" > ~/.dmc/tmp/${NAME}.input
- head -n 1 ~/.dmc/tmp/${NAME}.lock > /dev/stderr
- cat ~/.dmc/tmp/${NAME}.output
-}
-
-start_account_daemons () {
- chkcfg
- i=0
- for a in ~/.dmc/acc/* ; do
- ( . $a ; acc_daemon ) &
- i=$(($i+1))
- sleep 1
- done
- if [ $i = 0 ]; then
- echo "No accounts defined in ~/.dmc/acc"
- exit 1
- fi
-}
-
-print_account_template () {
- echo "NAME='test'"
- echo "SSL=0"
- echo "LIMIT=50 # get only 50 mails for each folder"
- echo "PROTOCOL='pop3' # imap4"
- echo "HOST=serverhost.com"
- echo "PORT=110"
- echo "#SEND=acc-name"
- echo "SEND=!msmtp"
- echo "ONLINE=0"
- echo "MAIL=username@domain"
- echo "USER='username'"
- echo "PASS='password'"
-}
-
-edit_message () {
- chkcfg
- OUTDIR=~/.dmc/box/${NAME}/out
- mkdir -p ${OUTDIR}
- OUT="`mktemp ${OUTDIR}/mail.XXXXXX`"
- echo "X-Mailer: dmc v${VERSION}" > $OUT
- echo "From: ${MAIL}" >> $OUT
- echo "To: ${TO}" >> $OUT
- echo "Subject: ${SUBJECT}" >> $OUT
- echo "" >> $OUT
- echo "" >> $OUT
- if [ -e ~/.dmc/box/${NAME}/signature ]; then
- echo "---" >> $OUT
- cat ~/.dmc/box/${NAME}/signature >> $OUT
- else
- if [ -e ~/.dmc/signature ]; then
- echo "---" >> $OUT
- cat ~/.dmc/signature >> $OUT
- fi
- fi
- ${EDITOR} ${OUT}
- if [ -z "`cat ${OUT}`" ]; then
- echo "Mail aborted"
- rm -f "${OUT}"
- else
- ln -fs "${OUT}" ~/.dmc/mail.last
- fi
-}
-
-add_attachment () {
- chkcfg
- OUT="`readlink ~/.dmc/mail.last`"
- if [ -z "${OUT}" ]; then
- echo "No ~/.dmc/mail.last found. 'dmc -m' or manual symlink required."
- else
- mkdir -p "${OUT}.d"
- if [ -f "$1" ]; then
- FILE="`basename \"$1\"`"
- ln -fs "$1" "${OUT}.d/${FILE}"
- else
- echo "Cannot find \"$1\""
- fi
- fi
-}
-
-send_message () {
- chkcfg
- FILE=$1
- if [ ! -e "${FILE}" ]; then
- echo "Cannot find '${FILE}'"
- exit 1
- fi
- # TODO: find better name for the auto mode
- if [ -e "${FILE}.d" ]; then
- TMP="`mktemp ~/.dmc/tmp/mail.XXXXXX`"
- cat $FILE | dmc-pack `ls ${FILE}.d/*` > $TMP
- else
- TMP=$FILE
- fi
- if [ "${SEND}" = "!msmtp" ]; then
- TO="`dmc-filter -v To: < $FILE`"
- SJ="`dmc-filter -v Subject: < $FILE`"
- echo "Sending mail to $TO (${SJ})..."
-# HOST=`dmc-smtp ${TO}`
- msmtp "--user=${USER}" "--from=${MAIL}" $TO < ${TMP}
- return $?
- elif [ "`echo \"${SEND}\" | grep '|'`" ]; then
- echo "=> cat $1 ${SEND}"
- # TODO: setup environment for $TO $SUBJECT ...
- eval cat ${TMP} ${SEND}
- else
- echo "SEND method '${SEND}' not supported"
- fi
- [ -e "${FILE}.d" ] && rm -f $TMP
- return 0
-}
-
-pull_mails () {
- chkcfg
- echo "Pulling mails from account '${NAME}'"
- # This is pop3-only
- i=1
- while [ ! "$LIMIT" = "$i" ] ; do
- dmc -c cat $i > ~/.dmc/box/${NAME}/in/$i.eml 2> ~/.dmc/tmp/${NAME}.tmp
- if [ -n "`cat ~/.dmc/tmp/${NAME}.tmp | grep 'cat 0'`" ]; then
- rm -f ~/.dmc/box/${NAME}/in/$i.eml
- echo "EOF $i"
- cat ~/.dmc/tmp/${NAME}.tmp
- break
- else
- size=`du -hs ~/.dmc/box/${NAME}/in/$i.eml | awk '{print \$1}'`
- echo "got $i $size $(cat ~/.dmc/tmp/${NAME}.tmp)"
- fi
- i=$(($i+1))
- done
-}
-
-ign () { : ; }
-
-case "$1" in
-"start")
- start_account_daemons
- ;;
-"stop")
- cd ~/.dmc/tmp
- for a in *.input ; do
- [ "$a" = "*.input" ] && break # XXX ugly hack
- file=`echo $a|cut -d '.' -f 1`
- echo Stopping $file daemon
- echo exit > $a &
- sleep 1
- rm -f ~/.dmc/tmp/$a
- done
- rm -f ~/.dmc/tmp/* 2> /dev/null
- pkill cat
- trap ign TERM
- pkill -TERM dmc
- ;;
-"push")
- for a in ~/.dmc/acc/* ; do
- . $a
- [ ! -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
- [ -e "${b}.d" ] && mv ${b}.d ~/.dmc/box/${NAME}/sent
- else
- echo "There was an error sending the mail"
- fi
- done
- done
- ;;
-"pull")
- for a in ~/.dmc/acc/* ; do
- . $a
- mkdir -p ~/.dmc/box/${NAME}/in
- pull_mails
- done
- ;;
-"-e"|"--edit")
- if [ -n "$2" ]; then
- [ -z "`cat ~/.dmc/acc/$2`" ] && \
- print_account_template "$2" > ~/.dmc/acc/$2
- ${EDITOR} ~/.dmc/acc/$2
- if [ -z "`cat ~/.dmc/acc/$2`" ]; then
- rm -f ~/.dmc/acc/$2
- else
- echo "The '$2' account is now the default"
- ln -fs ~/.dmc/acc/$2 ~/.dmc/acc.default
- fi
- else
- ls ~/.dmc/acc | cat
- fi
- ;;
-"-c"|"--cmd")
- chkcfg
- if [ -z "$2" ]; then
- while [ ! "$A" = "exit" ] ; do
- printf "> "
- read A
- dmc_cmd "$A"
- done
- else
- shift
- dmc_cmd "$@"
- fi
- ;;
-"-s"|"--send")
- shift
- chkcfg
- if [ -z "$*" ]; then
- echo "Usage: dmc -s mail1 mail2 ..."
- exit 1
- fi
- for a in $* ; do
- send_message $a
- done
- ;;
-"-m"|"--mail")
- TO="$2"
- SUBJECT="$3"
- edit_message
- ;;
-"-A"|"--add-attachment")
- while [ -n "$2" ] ; do
- add_attachment $2
- shift
- done
- ;;
-"-a"|"--addr")
- if [ -n "$2" ]; then
- while [ -n "$2" ] ; do
- grep -e "$2" ~/.dmc/addrbook
- shift
- done
- else
- [ ! -f ~/.dmc/addrbook ] && touch ~/.dmc/addrbook
- ${EDITOR} ~/.dmc/addrbook
- fi
- ;;
-"-l"|"--list")
- cd ~/.dmc/box/${NAME}/in
- if [ -n "$2" ]; then
- if [ -f "$2.eml" ]; then
- cat $2.eml
- exit 0
- fi
- cd $2
- fi
- for a in `ls -rt *.eml` ; do
- printf "$a:\t\x1b[32m"
- dmc-filter Subject < $a | head -n 1
- printf "\x1b[0m \t- "
- dmc-filter To < $a | head -n 1
- printf " \t- "
- dmc-filter Date < $a | head -n 1
- done
- ;;
-"-v"|"--version")
- echo "dmc v${VERSION}"
- ;;
-"--help"|"-h")
- echo ${HELP}
- echo " -e account edit account information"
- echo " -a name show addressbook email for contact"
- echo " -A file add attachment to mail"
- echo " -c cmd run command for \$DMC_ACCOUNT or acc.default daemon"
- echo " -m addr subj create mail with default account"
- echo " -s file send email"
- echo " -l [mail/fold] list mails in folder or show mail"
- echo " -v show version"
- echo " -h show this help message"
- echo " start start mail daemons"
- echo " stop stop them all"
- echo " push send mails in box/*/out"
- echo " pull update box/*/in folders"
- ;;
-*)
- echo "${HELP}"
- ;;
-esac
-
-exit 0
diff --git a/dmc-cmd.c b/dmc-cmd.c
@@ -1,272 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-
-#define DMCDIR "/home/pancake/.dmc"
-#define EDITOR "vim"
-#define VERSION "0.1"
-
-static char prompt[64];
-static char **acc;
-
-static int dmcstart(const char *name) {
- return 0;
-}
-
-static int dmcstop(const char *name) {
- return 0;
-}
-
-static char *dmccmd(const char *cmd, char *err, int errlen) {
- return 0;
-}
-
-static int dmcpull(const char *name) {
- return 0;
-}
-
-static int dmcpush(const char *name) {
- return 0;
-}
-
-#define MAXACC 4
-static char **dmcaccounts() {
- struct dirent *de;
- static char *accounts[MAXACC];
- char buf[256], *defacc = NULL;
- DIR *dir;
- int acc = 0;
- memset (buf, 0, sizeof (buf));
- if (readlink (DMCDIR"/acc.default", buf, sizeof (buf))!=-1) {
- defacc = buf + strlen (buf)-1;
- while (*defacc != '/')
- defacc--;
- accounts[acc++] = strdup (++defacc);
- } else fprintf (stderr, "No default account defined.\n");
- dir = opendir (DMCDIR"/acc");
- while ((de = readdir (dir)))
- if (*de->d_name != '.' && (!defacc || strcmp (de->d_name, defacc)))
- accounts[acc++] = strdup (de->d_name);
- accounts[acc] = NULL;
- return accounts;
-}
-
-static void charrfree(char **ptr) {
- char **p = ptr;
- while (*p) {
- free(*p);
- p++;
- }
- *ptr = NULL;
-}
-
-static int dmcline(const char *line) {
- char err[128];
- char *ptr = strchr (line, ' ');
- if (ptr)
- *ptr = '\0';
- if (!strcmp (line, "?")) {
- printf ("Usage: push pull exit\n");
- } else
- if (!strcmp (line, "push")) {
- dmcpush (acc[0]);
- } else
- if (!strcmp (line, "pull")) {
- dmcstart (acc[0]);
- dmcpull (acc[0]);
- dmcstop (acc[0]);
- } else
- if (!strcmp (line, "exit")) {
- 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);
- } else fprintf (stderr, "## No reply\n");
- }
- return 1;
-}
-
-static int usage(const char *argv0, int lon) {
- fprintf (stderr, "Usage: %s [-hv] [-s file] [-e acc] [-a addr] [-m [A|S A]] [-l [box]]\n", argv0);
- if (lon) {
- fprintf (stderr,
- " -m [A|S A .. ] ; create mail (Subject, Address, ..)\n"
- " -c [cmd] ; command shell\n"
- " -e [acc] ; list/edit/set default accounts\n"
- " -a [addr] ; grep in addressbook\n"
- " -l [box] ; list mails in specified box of def account\n"
- " -s [file] ; send mail\n"
- " -v ; show version\n"
- "");
- }
- return 0;
-}
-
-static int fexist(const char *path) {
- struct stat st;
- int ret = stat (path, &st);
- return (ret != -1);
-}
-
-static int fsize(const char *path) {
- FILE *fd = fopen (path, "r");
- int len = 0;
- if (fd) {
- len = fseek (fd, 0, SEEK_END);
- fclose (fd);
- }
- return len;
-}
-
-int main(int argc, char **argv) {
- char file[128], line[128];
- struct dirent *de;
- DIR *dir;
- int i;
-
- if (argc < 2)
- return usage (argv[0], 0);
-
- acc = dmcaccounts ();
-
- if (argv[1][0] == '-')
- switch (argv[1][1]) {
- case 'l':
- if (argc>2) {
- snprintf (line, sizeof (line), DMCDIR"/box/%s/in/%s.eml", acc[0], argv[2]);
- if (fexist (line)) {
- snprintf (line, sizeof (line), "cat '"DMCDIR"/box/%s/in/%s.eml'",
- acc[0], argv[2]);
- system (line); // implement native cat
- break;
- }
- snprintf (line, sizeof (line), DMCDIR"/box/%s", argv[2]);
- } else snprintf (line, sizeof (line), DMCDIR"/box/%s/in", acc[0]);
- charrfree (acc);
- if ((dir = opendir (line))) {
- while ((de = readdir (dir))) {
- if (*de->d_name!='.')
- printf ("%s:\n", de->d_name);
- }
- closedir (dir);
- }
- break;
- case 'v':
- printf ("dmc v"VERSION"\n");
- break;
- case 's':
- case 'm':
- fprintf (stderr, "TODO\n");
- break;
- case 'e':
- if (argc<3) {
- for (i=0; acc[i]; i++)
- printf ("%s\n", acc[i]);
- } else {
- snprintf (file, sizeof (file), DMCDIR"/acc/%s", argv[2]);
- if (!fexist (file)) {
- /* create template */
- FILE *fd = fopen (file, "w");
- if (fd) {
- fprintf (fd,
- "NAME=test\n"
- "SSL=0\n"
- "LIMIT=50 # get only 50 mails for each folder\n"
- "PROTOCOL=pop3 # imap4\n"
- "HOST=serverhost.com\n"
- "PORT=110\n"
- "#SEND=acc-name\n"
- "SEND=!msmtp\n"
- "MAIL=username@domain.com\n"
- "USER=username\n"
- "PASS=password\n");
- fclose (fd);
- } else {
- fprintf (stderr, "Cannot write in %s\n", file);
- return 1;
- }
- }
- snprintf (line, sizeof (line), EDITOR" %s", file);
- system (line);
- if (fsize(file)<32) {
- printf ("Abort\n");
- unlink (file);
- } else {
- printf ("Default account has changed.\n");
- unlink (DMCDIR"/acc.default");
- symlink (file, DMCDIR"/acc.default");
- }
- }
- charrfree (acc);
- return 0;
- case 'a':
- if (argc<3) {
- snprintf (line, sizeof (line), EDITOR" '"DMCDIR"/addrbook'");
- system (line);
- } else {
- FILE *fd = fopen (DMCDIR"/addrbook", "r");
- if (fd) {
- while (!feof (fd)) {
- fgets (line, sizeof (line), fd);
- for (i=2; i<argc; i++) {
- if (strstr (line, argv[i]))
- printf ("%s", line);
- }
- }
- fclose (fd);
- }
- }
- break;
- case 'c':
- strcpy (prompt, "dmc> ");
- do {
- write (1, prompt, strlen (prompt));
- fgets(line, sizeof (line), stdin);
- if (feof (stdin))
- strcpy (line, "exit");
- else line[strlen (line)-1] = '\0';
- } while (dmcline (line));
- break;
- default:
- return usage (argv[0], 1);
- }
-
- charrfree (acc);
- return 0;
-}
-
-#if 0
- $ echo pull | dmc-cmd
- $ dmc-cmd pull
- $ dmc
- dmc> ls
- nopcode
- radare
- dmc> use nopcode
- # start dmc-pop3 connection
- dmc/nopcode> login [user/pass]
- # +OK (user/pass) are optional
- dmc/nopcode> ls
-
-Commands
-========
-Handled by dmc-cmd:
- ? : alias for help
- use <accountname>
- pull
- push
- help
-
-Handled by dmc-pop3|imap4|...:
- exit: handled by child
- cd <change directory>
- help
-
-#endif
diff --git a/dmc.c b/dmc.c
@@ -0,0 +1,527 @@
+/* dmc - dynamic mail client
+ * See LICENSE file for copyright and license details.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include "config.h"
+
+static char **dmcaccounts();
+static char prompt[64];
+static char **acc, *defacc = NULL;
+static int dmc_in[2], dmc_out[2], dmc_err[2];
+static int dmc_pid = -1;
+static fd_set rfds, wfds;
+
+static void dmcstop();
+static int dmcsend(const char *file);
+static int fexist(const char *path);
+extern int errno;
+
+static void dmcinit() {
+ if (!fexist (DMCDIR))
+ if (mkdir (DMCDIR, DIRPERM) == -1) {
+ fprintf (stderr, "Cannot create "DMCDIR"\n");
+ exit (1);
+ }
+ mkdir (DMCDIR"/tmp", DIRPERM);
+ mkdir (DMCDIR"/box", DIRPERM);
+ mkdir (DMCDIR"/acc", DIRPERM);
+ acc = dmcaccounts ();
+ defacc = acc[0];
+ signal (SIGINT, dmcstop);
+ atexit (dmcstop);
+}
+
+static char *cfgget(const char *key) {
+ FILE *fd;
+ char file[128], line[128], *ptr, *ret = NULL;
+ snprintf (file, sizeof (file), DMCDIR"/acc/%s", defacc);
+ if ((fd = fopen (file, "r"))) {
+ int len = strlen (key);
+ while (!feof (fd)) {
+ fgets (line, sizeof (line), fd);
+ if (!memcmp (line, key, len)) {
+ ptr = strchr (line, '#');
+ if (ptr)
+ for (*ptr=0, ptr--; ptr != line && (*ptr==' ' || *ptr=='\t'); ptr--)
+ *ptr = 0;
+ line [strlen (line)-1] = 0;
+ ret = strdup (line+len);
+ break;
+ }
+ }
+ fclose (fd);
+ }
+ return ret;
+}
+
+static char *gethdr(const char *path, const char *file, const char *hdr) {
+ char line[1024], *ret = NULL;
+ FILE *fd;
+ snprintf (line, sizeof (line), "%s/%s", path, file);
+ fd = fopen (line, "r");
+ if (fd) {
+ int len = strlen (hdr);
+ while (!feof (fd)) {
+ fgets (line, sizeof (line), fd);
+ if (!memcmp (line, hdr, len)) {
+ line[strlen (line)-2] = '\0';
+ ret = strdup (line+len);
+ break;
+ }
+ }
+ fclose (fd);
+ }
+ return ret;
+}
+
+/* server */
+static int dmcstart(const char *name) {
+ char *host, *port;
+ pipe (dmc_in);
+ pipe (dmc_out);
+ pipe (dmc_err);
+ dmc_pid = fork ();
+ signal (SIGPIPE, SIG_IGN);
+ switch (dmc_pid) {
+ case -1:
+ fprintf (stderr, "Cannot fork\n");
+ exit (1);
+ case 0:
+ dup2 (dmc_in[0], 0);
+ close (dmc_in[0]);
+ close (dmc_in[1]);
+
+ dup2 (dmc_out[1], 1);
+ close (dmc_out[0]);
+ close (dmc_out[1]);
+
+ dup2 (dmc_err[1], 2);
+ close (dmc_err[0]);
+ close (dmc_err[1]);
+
+ host = cfgget ("HOST=");
+ port = cfgget ("PORT=");
+ execl (PREFIX"/bin/dmc-pop3", "dmc-pop3", host, port, NULL);
+ free (host);
+ free (port);
+ exit (1);
+ default:
+ close (dmc_out[1]);
+ close (dmc_err[1]);
+ close (dmc_in[0]);
+ break;
+ }
+ return 0;
+}
+
+static void dmckill(int sig) {
+ fprintf (stderr, "Killed.\n");
+ kill (dmc_pid, SIGKILL);
+}
+
+static void dmcstop() {
+ if (dmc_pid != -1) {
+ const char *cmd = "exit\n";
+ write (dmc_in[1], cmd, strlen (cmd));
+ signal (SIGALRM, dmckill);
+ alarm (2);
+ waitpid (dmc_pid, NULL, 0);
+ signal (SIGALRM, NULL);
+ alarm (0);
+ dmc_pid = -1;
+
+ // duppy
+ close (dmc_in[0]);
+ close (dmc_in[1]);
+ close (dmc_out[0]);
+ close (dmc_out[1]);
+ close (dmc_err[0]);
+ close (dmc_err[1]);
+ }
+}
+
+static char *dmccmd(const char *cmd, char *err, int errlen) {
+ static char buf[4096];
+ int ret, nfd;
+
+ if (dmc_pid == -1) {
+ printf ("Use 'start' or '?'\n");
+ return NULL;
+ }
+ for (;;) {
+ FD_ZERO (&rfds);
+ FD_ZERO (&wfds);
+ FD_SET (dmc_out[0], &rfds);
+ FD_SET (dmc_err[0], &rfds);
+ FD_SET (dmc_in[1], &wfds);
+ nfd = select (dmc_err[0] + 1, &rfds, &wfds, NULL, NULL);
+ if (nfd < 0)
+ break;
+ if (FD_ISSET (dmc_out[0], &rfds)) {
+ ret = read (dmc_out[0], buf, sizeof (buf)-1);
+ if (ret>0) {
+ buf[ret-1] = 0;
+ printf ("-(out)-> (%s)\n", buf);
+ break;
+ }
+ } else
+ if (FD_ISSET (dmc_err[0], &rfds)) {
+ ret = read (dmc_err[0], buf, sizeof (buf)-1);
+ if (ret>0) {
+ buf[ret-1] = 0;
+ printf ("-(err)-> (%s)\n", buf);
+ }
+ } else
+ if (FD_ISSET (dmc_in[1], &wfds)) {
+ if (cmd && *cmd && *cmd != '\n') {
+ snprintf (buf, sizeof (buf), "%s\n", cmd);
+ write (dmc_in[1], buf, strlen (buf));
+ printf ("write (%s)\n", cmd);
+ cmd = NULL;
+ }
+ }
+ }
+ return buf;
+}
+
+static int dmcpull(const char *name) {
+ return 0;
+}
+
+static void dmcpush(const char *name) {
+ struct dirent *de;
+ char path[256], file[512];
+ DIR *dir;
+ int i;
+
+ for (i=0; acc[i]; i++) {
+ snprintf (path, sizeof (path), DMCDIR"/box/%s/out", acc[i]);
+ dir = opendir (path);
+ while ((de = readdir (dir)))
+ if (*de->d_name != '.') {
+ snprintf (file, sizeof (file), "%s/%s", path, de->d_name);
+ printf ("--> %s\n", file);
+ dmcsend (file);
+ snprintf (file, sizeof (file), "rm -rf %s*", file);
+ printf ("--> (%s)\n", file);
+ //system (file);
+ }
+ closedir (dir);
+ }
+}
+
+/* utils */
+static int fexist(const char *path) {
+ struct stat st;
+ int ret = stat (path, &st);
+ return (ret != -1);
+}
+
+static int fsize(const char *path) {
+ FILE *fd = fopen (path, "r");
+ int len = 0;
+ if (fd) {
+ fseek (fd, 0, SEEK_END);
+ len = ftell (fd);
+ fclose (fd);
+ }
+ return len;
+}
+
+#define MAXACC 4
+static char **dmcaccounts() {
+ struct dirent *de;
+ static char *accounts[MAXACC];
+ char buf[256], *defacc = NULL;
+ DIR *dir;
+ int acc = 0;
+ memset (buf, 0, sizeof (buf));
+ if (readlink (DMCDIR"/acc.default", buf, sizeof (buf))!=-1) {
+ defacc = buf + strlen (buf)-1;
+ while (*defacc != '/')
+ defacc--;
+ accounts[acc++] = strdup (++defacc);
+ } else fprintf (stderr, "No default account defined.\n");
+ dir = opendir (DMCDIR"/acc");
+ while ((de = readdir (dir)) && acc<MAXACC-2)
+ if (de->d_type == DT_REG)
+ if (*de->d_name != '.' && (!defacc || strcmp (de->d_name, defacc)))
+ accounts[acc++] = strdup (de->d_name);
+ accounts[acc] = NULL;
+ return accounts;
+}
+
+static void charrfree(char **ptr) {
+ char **p = ptr;
+ while (*p) {
+ free(*p);
+ p++;
+ }
+ *ptr = NULL;
+}
+
+static int dmcsend(const char *file) {
+ char line[512];
+ char *user = cfgget ("USER=");
+ char *mail = cfgget ("MAIL=");
+ char *to = gethdr ("/", file, "To: ");
+ /* TODO: Implement non-msmtp method */
+ snprintf (line, sizeof (line),
+ "dmc-pack `ls %s.d/* 2>/dev/null` < %s "
+ "| msmtp --user=\"%s\" --from=\"%s\" \"%s\" < %s",
+ file, file,
+ user, mail, to, file);
+ if (system (line) != 0) {
+ fprintf (stderr, "Error ocurred while sending %s\n", file);
+ return 0;
+ } else fprintf (stderr, "Sent.\n");
+ return 1;
+}
+
+static int dmcline(const char *line) {
+ char err[128];
+ char *ptr = strchr (line, ' ');
+ if (ptr)
+ *ptr = '\0';
+ if (!strcmp (line, "?")) {
+ printf ("Usage: start stop push pull exit ls cat ..\n");
+ } else
+ if (!strcmp (line, "start")) {
+ dmcstart (acc[0]);
+ ptr = dmccmd ("start", err, sizeof (err));
+ } else
+ if (!strcmp (line, "stop")) {
+ dmcstop ();
+ } else
+ if (!strcmp (line, "push")) {
+ dmcpush (acc[0]);
+ } else
+ if (!strcmp (line, "pull")) {
+ if (dmcstart (acc[0])) {
+ dmcpull (acc[0]);
+ dmcstop ();
+ }
+ } else
+ if (!strcmp (line, "exit")) {
+ return 0;
+ } else {
+ if (ptr)
+ *ptr = ' ';
+ /* bypass to child */
+ ptr = dmccmd (line, err, sizeof (err));
+ if (ptr) {
+ printf ("%s\n", ptr);
+ fprintf (stderr, "%s\n", err);
+ //free (ptr);
+ } else fprintf (stderr, "## No reply\n");
+ }
+ return 1;
+}
+
+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"
+ "");
+ }
+ return 0;
+}
+
+static int dmcmail(const char *addr, const char *subj) {
+ const char *from = "todo@from.com";
+ char file[128], line[128];
+ int fd;
+ snprintf (file, sizeof (file), DMCDIR"/box/%s/out/mail.XXXXXX", acc[0]);
+ fd = mkstemp (file);
+ if (fd != -1) {
+ snprintf (line, sizeof (line),
+ "X-Mailer: dmc v"VERSION"\n"
+ "From: %s\n"
+ "To: %s\n"
+ "Subject: %s\n\n\n", from, addr, subj);
+ write (fd, line, strlen (line));
+ close (fd);
+ snprintf (line, sizeof (line), EDITOR" %s", file);
+ system (line);
+ if (fsize (file)<32) {
+ fprintf (stderr, "Aborted\n");
+ unlink (file);
+ } else symlink (file, DMCDIR"/mail.last");
+ } else fprintf (stderr, "Cannot create '%s'\n", line);
+ return 0;
+}
+
+static void dmcattach(const char *file) {
+ char path[256];
+ const char *name = file + strlen (file)-1;
+ while (*name!='/' && name>file)
+ name--;
+ name++;
+ if (readlink (DMCDIR"/mail.last", path, sizeof (path)-10)!=-1) {
+ strcat (path, ".d/");
+ mkdir (path, 0750);
+ strcat (path, name);
+ symlink (file, path);
+ } else fprintf (stderr, "Cannot attach '%s'\n", file);
+}
+
+int main(int argc, char **argv) {
+ char file[128], line[128];
+ struct dirent *de;
+ DIR *dir;
+ int i;
+
+ if (argc < 2)
+ return usage (argv[0], 0);
+
+ dmcinit ();
+ if (strcmp (argv[1], "-e")) {
+ if (!acc[0]) {
+ fprintf (stderr, "Use 'dmc -e' to configure the account\n");
+ return 1;
+ }
+ }
+
+ if (argv[1][0] == '-')
+ switch (argv[1][1]) {
+ case 'l':
+ if (argc>2) {
+ snprintf (line, sizeof (line), DMCDIR"/box/%s/in/%s.eml", acc[0], argv[2]);
+ if (fexist (line)) {
+ snprintf (line, sizeof (line), "cat '"DMCDIR"/box/%s/in/%s.eml'",
+ acc[0], argv[2]);
+ system (line); // implement native cat
+ break;
+ }
+ snprintf (line, sizeof (line), DMCDIR"/box/%s", argv[2]);
+ } else snprintf (line, sizeof (line), DMCDIR"/box/%s/in", acc[0]);
+ if ((dir = opendir (line))) {
+ while ((de = readdir (dir))) {
+ if (*de->d_name!='.') {
+ char *subj = gethdr (line, de->d_name, "Subject: ");
+ char *from = gethdr (line, de->d_name, "From: ");
+ printf ("%s:\t%s\n\t%s\n", de->d_name, subj, from);
+ free (from);
+ free (subj);
+ }
+ }
+ closedir (dir);
+ }
+ break;
+ case 'A':
+ for (i=2; i<argc; i++)
+ dmcattach (argv[i]);
+ break;
+ case 'v':
+ printf ("dmc v"VERSION"\n");
+ break;
+ case 's':
+ if (argc>2)
+ dmcsend (argv[2]);
+ else fprintf (stderr, "Usage: dmc-cmd [-s file]\n");
+ break;
+ case 'm':
+ {
+ char *addr = "";
+ char *subj = "";
+ if (argc>2)
+ addr = argv[2];
+ if (argc>3)
+ subj = argv[3];
+ dmcmail (addr, subj);
+ }
+ break;
+ case 'e':
+ if (argc<3) {
+ for (i=0; acc[i]; i++)
+ printf ("%s\n", acc[i]);
+ } else {
+ snprintf (file, sizeof (file), DMCDIR"/acc/%s", argv[2]);
+ if (!fexist (file)) {
+ /* create template */
+ FILE *fd = fopen (file, "w");
+ if (fd) {
+ fprintf (fd,
+ "NAME=test\n"
+ "SSL=0\n"
+ "LIMIT=50 # get only 50 mails for each folder\n"
+ "PROTOCOL=pop3 # imap4\n"
+ "HOST=serverhost.com\n"
+ "PORT=110\n"
+ "#SEND=acc-name\n"
+ "SEND=!msmtp\n"
+ "MAIL=username@domain.com\n"
+ "USER=username\n"
+ "PASS=password\n");
+ fclose (fd);
+ } else {
+ fprintf (stderr, "Cannot write in %s\n", file);
+ return 1;
+ }
+ }
+ snprintf (line, sizeof (line), EDITOR" %s", file);
+ system (line);
+ if (fsize(file)<32) {
+ printf ("Abort\n");
+ unlink (file);
+ } else {
+ printf ("Default account has changed.\n");
+ unlink (DMCDIR"/acc.default");
+ symlink (file, DMCDIR"/acc.default");
+ }
+ }
+ break;
+ case 'a':
+ if (argc<3) {
+ snprintf (line, sizeof (line), EDITOR" '"DMCDIR"/addrbook'");
+ system (line);
+ } else {
+ FILE *fd = fopen (DMCDIR"/addrbook", "r");
+ if (fd) {
+ while (!feof (fd)) {
+ fgets (line, sizeof (line), fd);
+ for (i=2; i<argc; i++) {
+ if (strstr (line, argv[i]))
+ printf ("%s", line);
+ }
+ }
+ fclose (fd);
+ }
+ }
+ break;
+ case 'c':
+ strcpy (prompt, "dmc> ");
+ do {
+ write (1, prompt, strlen (prompt));
+ fgets(line, sizeof (line), stdin);
+ if (feof (stdin))
+ strcpy (line, "exit");
+ else line[strlen (line)-1] = '\0';
+ } while (dmcline (line));
+ dmcstop ();
+ break;
+ default:
+ return usage (argv[0], 1);
+ }
+
+ charrfree (acc);
+ return 0;
+}
diff --git a/dmc.sh b/dmc.sh
@@ -0,0 +1,321 @@
+#!/bin/sh
+# dmc - dynamic mail client
+# See LICENSE file for copyright and license details.
+
+VERSION="0.1"
+HELP="Usage: dmc [-hv] [-e acc] [-a addr] [-m addr subj] [-A file] [-s msg] [action]"
+
+[ -z "${EDITOR}" ] && EDITOR=vim
+mkdir -p ~/.dmc/mail
+mkdir -p ~/.dmc/tmp
+mkdir -p ~/.dmc/acc
+[ -e ~/.dmc/acc.default ] && . ~/.dmc/acc.default
+
+chkcfg () {
+ if [ -z "${NAME}" ]; then
+ echo "No selected mail account. Use 'dmc -e'"
+ exit 1
+ fi
+}
+
+acc_daemon () {
+ chkcfg
+ LOCK=~/.dmc/tmp/${NAME}.lock
+ INPUT=~/.dmc/tmp/${NAME}.input
+ OUTPUT=~/.dmc/tmp/${NAME}.output
+
+ echo "Starting $NAME account $PROTOCOL daemon..."
+
+ rm -f "${LOCK}" "${INPUT}" "${OUTPUT}"
+ mkfifo "${LOCK}" "${INPUT}"
+
+ # wait 1 connect message and 1 login message
+ (head -n 2 ${LOCK} ; dmc_cmd "login ${USER} ${PASS}" ; dmc_cmd "ls") &
+ (while : ; do cat ${INPUT} 2> /dev/null ; done) | \
+ dmc-${PROTOCOL} ${HOST} ${PORT} ${SSL} 2> ${OUTPUT} > ${LOCK}
+ rm -f "${LOCK}" "${INPUT}" "${OUTPUT}"
+}
+
+dmc_cmd () {
+ [ -z "$1" ] && return
+ echo "$@" > ~/.dmc/tmp/${NAME}.input
+ head -n 1 ~/.dmc/tmp/${NAME}.lock > /dev/stderr
+ cat ~/.dmc/tmp/${NAME}.output
+}
+
+start_account_daemons () {
+ chkcfg
+ i=0
+ for a in ~/.dmc/acc/* ; do
+ ( . $a ; acc_daemon ) &
+ i=$(($i+1))
+ sleep 1
+ done
+ if [ $i = 0 ]; then
+ echo "No accounts defined in ~/.dmc/acc"
+ exit 1
+ fi
+}
+
+print_account_template () {
+ echo "NAME='test'"
+ echo "SSL=0"
+ echo "LIMIT=50 # get only 50 mails for each folder"
+ echo "PROTOCOL='pop3' # imap4"
+ echo "HOST=serverhost.com"
+ echo "PORT=110"
+ echo "#SEND=acc-name"
+ echo "SEND=!msmtp"
+ echo "ONLINE=0"
+ echo "MAIL=username@domain"
+ echo "USER='username'"
+ echo "PASS='password'"
+}
+
+edit_message () {
+ chkcfg
+ OUTDIR=~/.dmc/box/${NAME}/out
+ mkdir -p ${OUTDIR}
+ OUT="`mktemp ${OUTDIR}/mail.XXXXXX`"
+ echo "X-Mailer: dmc v${VERSION}" > $OUT
+ echo "From: ${MAIL}" >> $OUT
+ echo "To: ${TO}" >> $OUT
+ echo "Subject: ${SUBJECT}" >> $OUT
+ echo "" >> $OUT
+ echo "" >> $OUT
+ if [ -e ~/.dmc/box/${NAME}/signature ]; then
+ echo "---" >> $OUT
+ cat ~/.dmc/box/${NAME}/signature >> $OUT
+ else
+ if [ -e ~/.dmc/signature ]; then
+ echo "---" >> $OUT
+ cat ~/.dmc/signature >> $OUT
+ fi
+ fi
+ ${EDITOR} ${OUT}
+ if [ -z "`cat ${OUT}`" ]; then
+ echo "Mail aborted"
+ rm -f "${OUT}"
+ else
+ ln -fs "${OUT}" ~/.dmc/mail.last
+ fi
+}
+
+add_attachment () {
+ chkcfg
+ OUT="`readlink ~/.dmc/mail.last`"
+ if [ -z "${OUT}" ]; then
+ echo "No ~/.dmc/mail.last found. 'dmc -m' or manual symlink required."
+ else
+ mkdir -p "${OUT}.d"
+ if [ -f "$1" ]; then
+ FILE="`basename \"$1\"`"
+ ln -fs "$1" "${OUT}.d/${FILE}"
+ else
+ echo "Cannot find \"$1\""
+ fi
+ fi
+}
+
+send_message () {
+ chkcfg
+ FILE=$1
+ if [ ! -e "${FILE}" ]; then
+ echo "Cannot find '${FILE}'"
+ exit 1
+ fi
+ # TODO: find better name for the auto mode
+ if [ -e "${FILE}.d" ]; then
+ TMP="`mktemp ~/.dmc/tmp/mail.XXXXXX`"
+ cat $FILE | dmc-pack `ls ${FILE}.d/*` > $TMP
+ else
+ TMP=$FILE
+ fi
+ if [ "${SEND}" = "!msmtp" ]; then
+ TO="`dmc-filter -v To: < $FILE`"
+ SJ="`dmc-filter -v Subject: < $FILE`"
+ echo "Sending mail to $TO (${SJ})..."
+# HOST=`dmc-smtp ${TO}`
+ msmtp "--user=${USER}" "--from=${MAIL}" $TO < ${TMP}
+ return $?
+ elif [ "`echo \"${SEND}\" | grep '|'`" ]; then
+ echo "=> cat $1 ${SEND}"
+ # TODO: setup environment for $TO $SUBJECT ...
+ eval cat ${TMP} ${SEND}
+ else
+ echo "SEND method '${SEND}' not supported"
+ fi
+ [ -e "${FILE}.d" ] && rm -f $TMP
+ return 0
+}
+
+pull_mails () {
+ chkcfg
+ echo "Pulling mails from account '${NAME}'"
+ # This is pop3-only
+ i=1
+ while [ ! "$LIMIT" = "$i" ] ; do
+ dmc -c cat $i > ~/.dmc/box/${NAME}/in/$i.eml 2> ~/.dmc/tmp/${NAME}.tmp
+ if [ -n "`cat ~/.dmc/tmp/${NAME}.tmp | grep 'cat 0'`" ]; then
+ rm -f ~/.dmc/box/${NAME}/in/$i.eml
+ echo "EOF $i"
+ cat ~/.dmc/tmp/${NAME}.tmp
+ break
+ else
+ size=`du -hs ~/.dmc/box/${NAME}/in/$i.eml | awk '{print \$1}'`
+ echo "got $i $size $(cat ~/.dmc/tmp/${NAME}.tmp)"
+ fi
+ i=$(($i+1))
+ done
+}
+
+ign () { : ; }
+
+case "$1" in
+"start")
+ start_account_daemons
+ ;;
+"stop")
+ cd ~/.dmc/tmp
+ for a in *.input ; do
+ [ "$a" = "*.input" ] && break # XXX ugly hack
+ file=`echo $a|cut -d '.' -f 1`
+ echo Stopping $file daemon
+ echo exit > $a &
+ sleep 1
+ rm -f ~/.dmc/tmp/$a
+ done
+ rm -f ~/.dmc/tmp/* 2> /dev/null
+ pkill cat
+ trap ign TERM
+ pkill -TERM dmc
+ ;;
+"push")
+ for a in ~/.dmc/acc/* ; do
+ . $a
+ [ ! -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
+ [ -e "${b}.d" ] && mv ${b}.d ~/.dmc/box/${NAME}/sent
+ else
+ echo "There was an error sending the mail"
+ fi
+ done
+ done
+ ;;
+"pull")
+ for a in ~/.dmc/acc/* ; do
+ . $a
+ mkdir -p ~/.dmc/box/${NAME}/in
+ pull_mails
+ done
+ ;;
+"-e"|"--edit")
+ if [ -n "$2" ]; then
+ [ -z "`cat ~/.dmc/acc/$2`" ] && \
+ print_account_template "$2" > ~/.dmc/acc/$2
+ ${EDITOR} ~/.dmc/acc/$2
+ if [ -z "`cat ~/.dmc/acc/$2`" ]; then
+ rm -f ~/.dmc/acc/$2
+ else
+ echo "The '$2' account is now the default"
+ ln -fs ~/.dmc/acc/$2 ~/.dmc/acc.default
+ fi
+ else
+ ls ~/.dmc/acc | cat
+ fi
+ ;;
+"-c"|"--cmd")
+ chkcfg
+ if [ -z "$2" ]; then
+ while [ ! "$A" = "exit" ] ; do
+ printf "> "
+ read A
+ dmc_cmd "$A"
+ done
+ else
+ shift
+ dmc_cmd "$@"
+ fi
+ ;;
+"-s"|"--send")
+ shift
+ chkcfg
+ if [ -z "$*" ]; then
+ echo "Usage: dmc -s mail1 mail2 ..."
+ exit 1
+ fi
+ for a in $* ; do
+ send_message $a
+ done
+ ;;
+"-m"|"--mail")
+ TO="$2"
+ SUBJECT="$3"
+ edit_message
+ ;;
+"-A"|"--add-attachment")
+ while [ -n "$2" ] ; do
+ add_attachment $2
+ shift
+ done
+ ;;
+"-a"|"--addr")
+ if [ -n "$2" ]; then
+ while [ -n "$2" ] ; do
+ grep -e "$2" ~/.dmc/addrbook
+ shift
+ done
+ else
+ [ ! -f ~/.dmc/addrbook ] && touch ~/.dmc/addrbook
+ ${EDITOR} ~/.dmc/addrbook
+ fi
+ ;;
+"-l"|"--list")
+ cd ~/.dmc/box/${NAME}/in
+ if [ -n "$2" ]; then
+ if [ -f "$2.eml" ]; then
+ cat $2.eml
+ exit 0
+ fi
+ cd $2
+ fi
+ for a in `ls -rt *.eml` ; do
+ printf "$a:\t\x1b[32m"
+ dmc-filter Subject < $a | head -n 1
+ printf "\x1b[0m \t- "
+ dmc-filter To < $a | head -n 1
+ printf " \t- "
+ dmc-filter Date < $a | head -n 1
+ done
+ ;;
+"-v"|"--version")
+ echo "dmc v${VERSION}"
+ ;;
+"--help"|"-h")
+ echo ${HELP}
+ echo " -e account edit account information"
+ echo " -a name show addressbook email for contact"
+ echo " -A file add attachment to mail"
+ echo " -c cmd run command for \$DMC_ACCOUNT or acc.default daemon"
+ echo " -m addr subj create mail with default account"
+ echo " -s file send email"
+ echo " -l [mail/fold] list mails in folder or show mail"
+ echo " -v show version"
+ echo " -h show this help message"
+ echo " start start mail daemons"
+ echo " stop stop them all"
+ echo " push send mails in box/*/out"
+ echo " pull update box/*/in folders"
+ ;;
+*)
+ echo "${HELP}"
+ ;;
+esac
+
+exit 0
diff --git a/pack.c b/pack.c
@@ -147,11 +147,13 @@ static void mime_unpack (int xtr) {
}
int main(int argc, char **argv) {
- if (argc < 2 || !strcmp(argv[1], "-h")) {
+ if (argc < 2) {
+ mime_pack (argv+1, argc-1);
+ } else
+ if (!strcmp(argv[1], "-h")) {
fprintf (stderr, "Usage: %s [-hlu | attachment1 attachment2...] < mail\n", argv[0]);
return 1;
- }
- else if (!strcmp(argv[1], "-l"))
+ } else if (!strcmp(argv[1], "-l"))
mime_unpack (0);
else if (!strcmp(argv[1], "-u"))
mime_unpack (1);