Mercurial > hg > Applications > mh
diff uip/popi.c @ 0:bce86c4163a3
Initial revision
author | kono |
---|---|
date | Mon, 18 Apr 2005 23:46:02 +0900 |
parents | |
children | a6481689f99c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uip/popi.c Mon Apr 18 23:46:02 2005 +0900 @@ -0,0 +1,878 @@ +/* popi.c - POP initiator - for MPOP */ +#ifndef lint +static char ident[] = "@(#)$Id$"; +#endif lint + +#include "../h/mh.h" +#include "../h/formatsbr.h" +#include "../h/scansbr.h" +#include <errno.h> +#include <stdio.h> +#include <sys/types.h> +#ifdef SMTP +#include "../h/local.h" +#else /* SMTP */ +#include <sys/stat.h> +#endif /* SMTP */ +#include "../zotnet/mts.h" +#ifdef SYS5DIR +#include <stdlib.h> +#endif + +/* */ + +#ifndef RPOP +#define RPOPminc(a) (a) +#else +#define RPOPminc(a) 0 +#endif + +#ifndef APOP +#define APOPminc(a) (a) +#else +#define APOPminc(a) 0 +#endif + +#if !defined(BPOP) || defined(NNTP) +#define BPOPminc(a) (a) +#else +#define BPOPminc(a) 0 +#endif + +#ifndef SMTP +#define BULKminc(a) (a) +#else +#define BULKminc(a) 0 +#endif + +static struct swit switches[] = { +#define APOPSW 0 + "apop", APOPminc (-4), +#define NAPOPSW 1 + "noapop", APOPminc (-6), + +#define AUTOSW 2 + "auto", BPOPminc(-4), +#define NAUTOSW 3 + "noauto", BPOPminc(-6), + +#define BULKSW 4 + "bulk directory", BULKminc(-4), + +#define FORMSW 5 + "form formatfile", 0, + +#define FMTSW 6 + "format string", 5, + +#define HOSTSW 7 + "host host", 0, + +#define PROGSW 8 + "mshproc program", 0, + +#define RPOPSW 9 + "rpop", RPOPminc (-4), +#define NRPOPSW 10 + "norpop", RPOPminc (-6), + +#define USERSW 11 + "user user", 0, + +#define WIDSW 12 + "width columns", 0, + +#define HELPSW 13 + "help", 4, + + NULL, 0 +}; + +/* */ + +static char *bulksw = NULLCP; +static int snoop = 0; +static int width = 0; + +static char mailname[BUFSIZ]; + +static char *nfs = NULL; + +static struct msgs *mp; + +extern int errno; + +extern char response[]; + +static popi(), retr_action(); +#if defined(BPOP) && !defined(NNTP) +static msh(); +#endif +#ifdef SMTP +static do_bulk(); +#endif + +/* */ + +/* ARGSUSED */ + +main (argc, argv) +int argc; +char *argv[]; +{ + int autosw = 1, + noisy = 1, + rpop; + char *cp, + *maildir, + *folder = NULL, + *form = NULL, + *format = NULL, + *host = NULL, + *user = NULL, + *pass = NULL, + buf[100], + **ap, + **argp, + *arguments[MAXARGS]; + struct stat st; + + invo_name = r1bindex (argv[0], '/'); + mts_init (invo_name); + if (pophost && *pophost) + host = pophost; + if ((cp = getenv ("MHPOPDEBUG")) && *cp) + snoop++; + if ((cp = m_find (invo_name)) != NULL) { + ap = brkstring (cp = getcpy (cp), " ", "\n"); + ap = copyip (ap, arguments); + } + else + ap = arguments; + (void) copyip (argv + 1, ap); + argp = arguments; + + rpop = getuid () && !geteuid (); + +/* */ + + while (cp = *argp++) { + if (*cp == '-') + switch (smatch (++cp, switches)) { + case AMBIGSW: + ambigsw (cp, switches); + done (1); + case UNKWNSW: + adios (NULLCP, "-%s unknown", cp); + case HELPSW: + (void) sprintf (buf, "%s [+folder] [switches]", invo_name); + help (buf, switches); + done (1); + + case AUTOSW: + autosw = 1; + continue; + case NAUTOSW: + autosw = 0; + continue; + + case BULKSW: + if (!(bulksw = *argp++) || *bulksw == '-') + adios (NULLCP, "missing argument to %s", argp[-2]); + continue; + + case FORMSW: + if (!(form = *argp++) || *form == '-') + adios (NULLCP, "missing argument to %s", argp[-2]); + format = NULL; + continue; + case FMTSW: + if (!(format = *argp++) || *format == '-') + adios (NULLCP, "missing argument to %s", argp[-2]); + form = NULL; + continue; + + case WIDSW: + if (!(cp = *argp++) || *cp == '-') + adios (NULLCP, "missing argument to %s", argp[-2]); + width = atoi (cp); + continue; + + case HOSTSW: + if (!(host = *argp++) || *host == '-') + adios (NULLCP, "missing argument to %s", argp[-2]); + continue; + case USERSW: + if (!(user = *argp++) || *user == '-') + adios (NULLCP, "missing argument to %s", argp[-2]); + continue; + + case APOPSW: + rpop = -1; + continue; + case RPOPSW: + rpop = 1; + continue; + case NAPOPSW: + case NRPOPSW: + rpop = 0; + continue; + + case PROGSW: + if (!(mshproc = *argp++) || *mshproc == '-') + adios (NULLCP, "missing argument to %s", argp[-2]); + continue; + } + if (*cp == '+' || *cp == '@') { + if (folder) + adios (NULLCP, "only one folder at a time!"); + else + folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF); + } + else + adios (NULLCP, "usage: %s [+folder] [switches]", invo_name); + } + +/* */ + + if (!host) + adios (NULLCP, "usage: %s -host \"host\"", invo_name); + +#ifdef SMTP + if (bulksw) + do_bulk (host); +#endif + + if (user == NULL) + user = getusr (); + if (rpop > 0) + pass = getusr (); + else { + (void) setuid (getuid ()); + ruserpass (host, &user, &pass); + } + (void) sprintf (mailname, "PO box for %s@%s", user, host); + + if (pop_init (host, user, pass, snoop, rpop) == NOTOK) + adios (NULLCP, "%s", response); + if (rpop > 0) + (void) setuid (getuid ()); + + nfs = new_fs (form, format, FORMAT); + + if (!m_find ("path")) + free (path ("./", TFOLDER)); + if (!folder && !(folder = m_find (inbox))) + folder = defalt; + maildir = m_maildir (folder); + + if (stat (maildir, &st) == NOTOK) { + if (errno != ENOENT) + adios (maildir, "error on folder"); + cp = concat ("Create folder \"", maildir, "\"? ", NULLCP); + if (noisy && !getanswer (cp)) + done (1); + free (cp); + if (!makedir (maildir)) + adios (NULLCP, "unable to create folder %s", maildir); + } + + if (chdir (maildir) == NOTOK) + adios (maildir, "unable to change directory to"); + if (!(mp = m_gmsg (folder))) + adios (NULLCP, "unable to read folder %s", folder); + +#if defined(BPOP) && !defined(NNTP) + if (autosw) + msh (); + else +#endif + popi (); + + (void) pop_quit (); + + m_replace (pfolder, folder); + m_setvis (mp, 0); + m_sync (mp); + m_update (); + + done (0); + + /* NOTREACHED */ +} + +/* */ + +static struct swit popicmds[] = { +#define DELECMD 0 + "dele", 0, +#define LASTCMD 1 + "last", 0, +#define LISTCMD 2 + "list", 0, +#define NOOPCMD 3 + "noop", 0, +#define QUITCMD 4 + "quit", 0, +#define RETRCMD 5 + "retr", 0, +#define RSETCMD 6 + "rset", 0, +#define SCANCMD 7 + "scan", 0, +#define STATCMD 8 + "stat", 0, +#define TOPCMD 9 + "top", 0, +#if defined(BPOP) && !defined(NNTP) +#define MSHCMD 10 + "msh", 0, +#endif + + NULL, 0 +}; + +/* */ + +static popi () +{ + int eof; + + eof = 0; + for (;;) { + int i; + register char *cp; + char buffer[BUFSIZ]; + + if (eof) + return; + + printf ("(%s) ", invo_name); + for (cp = buffer; (i = getchar ()) != '\n'; ) { + if (i == EOF) { + (void) putchar ('\n'); + if (cp == buffer) + return; + eof = 1; + break; + } + + if (cp < buffer + sizeof buffer - 2) + *cp++ = i; + } + *cp = '\0'; + if (buffer[0] == '\0') + continue; + if (buffer[0] == '?') { + printf ("commands:\n"); + printsw (ALL, popicmds, ""); + printf ("type CTRL-D or use \"quit\" to leave %s\n", invo_name); + continue; + } + + if (cp = index (buffer, ' ')) + *cp = '\0'; + switch (i = smatch (buffer, popicmds)) { + case AMBIGSW: + ambigsw (buffer, popicmds); + continue; + case UNKWNSW: + printf ("%s unknown -- type \"?\" for help\n", buffer); + continue; + + case QUITCMD: + return; + + case STATCMD: + case DELECMD: + case NOOPCMD: + case LASTCMD: + case RSETCMD: + case TOPCMD: + if (cp) + *cp = ' '; + (void) pop_command ("%s%s", popicmds[i].sw, cp ? cp : ""); + printf ("%s\n", response); + break; + + case LISTCMD: + if (cp) + *cp = ' '; + if (pop_command ("%s%s", popicmds[i].sw, cp ? cp : "") + == OK) { + printf ("%s\n", response); + if (!cp) + for (;;) { + switch (pop_multiline ()) { + case DONE: + (void) strcpy (response, "."); + /* and fall... */ + case NOTOK: + printf ("%s\n", response); + break; + + case OK: + printf ("%s\n", response); + continue; + } + break; + } + } + break; + + case RETRCMD: + if (!cp) { + advise (NULLCP, "missing argument to %s", buffer); + break; + } + retr_action (NULLCP, OK); + (void) pop_retr (atoi (++cp), retr_action); + retr_action (NULLCP, DONE); + printf ("%s\n", response); + break; + + case SCANCMD: + { + char *dp, + *ep, + *fp; + + if (width == 0) + width = sc_width (); + + for (dp = nfs, i = 0; *dp; dp++, i++) + if (*dp == '\\' || *dp == '"' || *dp == '\n') + i++; + i++; + if ((ep = malloc ((unsigned) i)) == NULL) + adios (NULLCP, "out of memory"); + for (dp = nfs, fp = ep; *dp; dp++) { + if (*dp == '\n') { + *fp++ = '\\', *fp++ = 'n'; + continue; + } + if (*dp == '"' || *dp == '\\') + *fp++ = '\\'; + *fp++ = *dp; + } + *fp = '\0'; + + (void) pop_command ("xtnd scan %d \"%s\"", width, ep); + printf ("%s\n", response); + + free (ep); + } + break; + +#if defined(BPOP) && !defined(NNTP) + case MSHCMD: + msh (); + break; +#endif + } + } +} + +/* */ + +static int retr_action (rsp, flag) +char *rsp; +int flag; +{ + static FILE *fp; + + if (rsp == NULL) { + static int msgnum; + static char *cp; + + if (flag == OK) { + if ((mp = m_remsg (mp, 0, msgnum = mp -> hghmsg + 1)) == NULL) + adios (NULLCP, "unable to allocate folder storage"); + + cp = getcpy (m_name (mp -> hghmsg + 1)); + if ((fp = fopen (cp, "w+")) == NULL) + adios (cp, "unable to write"); + (void) chmod (cp, m_gmprot ()); + } + else { + struct stat st; + + (void) fflush (fp); + if (fstat (fileno (fp), &st) != NOTOK && st.st_size > 0) { + mp -> msgstats[msgnum] = EXISTS | UNSEEN; + mp -> msgflags |= SEQMOD; + + if (ferror (fp)) + advise (cp, "write error on"); + mp -> hghmsg = msgnum; + } + else + (void) unlink (cp); + + (void) fclose (fp), fp = NULL; + free (cp), cp = NULL; + } + + return; + } + + fprintf (fp, "%s\n", rsp); +} + +/* */ + +#if defined(BPOP) && !defined(NNTP) +static msh () +{ + int child_id, + vecp; + char buf1[BUFSIZ], + buf2[BUFSIZ], + *vec[9]; + + if (pop_fd (buf1, buf2) == NOTOK) + adios (NULLCP, "%s", response); + + vecp = 0; + vec[vecp++] = r1bindex (mshproc, '/'); + + switch (child_id = fork ()) { + case NOTOK: + adios ("fork", "unable to"); + + case OK: + vec[vecp++] = "-popread"; + vec[vecp++] = buf1; + vec[vecp++] = "-popwrite"; + vec[vecp++] = buf2; + vec[vecp++] = "-idname"; + vec[vecp++] = mailname; + vec[vecp++] = mailname; + vec[vecp] = NULL; + (void) execvp (mshproc, vec); + fprintf (stderr, "unable to exec "); + perror (mshproc); + _exit (-1); + + default: + (void) pidXwait (child_id, mshproc); + break; + } +} +#endif + +/* */ + +#ifdef SMTP +#include "../zotnet/mts.h" +#include "../mts/sendmail/smail.h" + + +static int dselect (d) +#ifdef SYS5DIR +register struct dirent *d; +#else +register struct direct *d; +#endif +{ + int i; + + if ((i = strlen (d -> d_name)) < sizeof "smtp" + || strncmp (d -> d_name, "smtp", sizeof "smtp" - 1)) + return 0; + return ((i -= (sizeof ".bulk" - 1)) > 0 + && !strcmp (d -> d_name + i, ".bulk")); +} + + +static int dcompar (d1, d2) +#ifdef SYS5DIR +struct dirent **d1, + **d2; +#else +struct direct **d1, + **d2; +#endif +{ + struct stat s1, + s2; + + if (stat ((*d1) -> d_name, &s1) == NOTOK) + return 1; + if (stat ((*d2) -> d_name, &s2) == NOTOK) + return -1; + return ((int) (s1.st_mtime - s2.st_mtime)); +} + + +static do_bulk (host) +char *host; +{ + register int i; + int n, + retval, + sm; +#ifdef SYS5DIR + struct dirent **namelist; +#else + struct direct **namelist; +#endif + + if (chdir (bulksw) == NOTOK) + adios (bulksw, "unable to change directory to"); + + if ((n = scandir (".", &namelist, dselect, dcompar)) == NOTOK) + adios (bulksw, "unable to scan directory"); + + sm = NOTOK; + for (i = 0; i < n; i++) { +#ifdef SYS5DIR + register struct dirent *d = namelist[i]; +#else + register struct direct *d = namelist[i]; +#endif + + if (sm == NOTOK) { + if (rp_isbad (retval = sm_init (NULLCP, host, 1, 1, snoop))) + adios (NULLCP, "problem initializing server: %s", + rp_string (retval)); + else + sm = OK; + } + + switch (retval = sm_bulk (d -> d_name)) { + default: + if (rp_isbad (retval)) + adios (NULLCP, "problem delivering msg %s: %s", + d -> d_name, rp_string (retval)); + /* else fall... */ + case RP_OK: + case RP_NO: + case RP_NDEL: + advise (NULLCP, "msg %s: %s", d -> d_name, rp_string (retval)); + break; + } + } + + if (sm == OK) { + register int j; + int l, + m; +#ifdef SYS5DIR + struct dirent **newlist; +#else + struct direct **newlist; +#endif + + while ((l = scandir (".", &newlist, dselect, dcompar)) > OK) { + m = 0; + + for (j = 0; j < l; j++) { +#ifdef SYS5DIR + register struct dirent *d = newlist[j]; +#else + register struct direct *d = newlist[j]; +#endif + + for (i = 0; i < n; i++) + if (strcmp (d -> d_name, namelist[i] -> d_name) == 0) + break; + if (i >= n) { + switch (retval = sm_bulk (d -> d_name)) { + default: + if (rp_isbad (retval)) + adios (NULLCP, "problem delivering msg %s: %s", + d -> d_name, rp_string (retval)); + /* else fall... */ + case RP_OK: + case RP_NO: + case RP_NDEL: + advise (NULLCP, "msg %s: %s", d -> d_name, + rp_string (retval)); + break; + } + + m = 1; + } + } + + for (i = 0; i < n; i++) + free ((char *) namelist[i]); + free ((char *) namelist); + namelist = newlist, n = l; + + if (!m) + break; + newlist = NULL; + } + } + + if (sm == OK && rp_isbad (retval = sm_end (OK))) + adios (NULLCP, "problem finalizing server: %s", rp_string (retval)); + + for (i = 0; i < n; i++) + free ((char *) namelist[i]); + free ((char *) namelist); + + free ((char *) namelist); + + done (0); +} +#endif +#if defined(SYS5DIR) && !defined(BSD42) && !defined(hpux) && !defined(sgi) && !defined(linux) +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)scandir.c 5.10 (Berkeley) 2/23/91"; +#endif /* LIBC_SCCS and not lint */ +/* + * Scan the directory dirname calling select to make a list of selected + * directory entries then sort using qsort and compare routine dcomp. + * Returns the number of entries and a pointer to a list of pointers to + * struct dirent (through namelist). Returns -1 if there were any errors. + */ +/* + * This code modified by Ted Nolan to take Solaris dirent structures + * and mollify gcc -traditional. In general, everything from BSD that + * didn't work is "ifdef notdef" ed out + * + * 3 Feb 94 + */ +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +/* #include <stdlib.h> */ +#include <string.h> +/* + * The DIRSIZ macro gives the minimum record length which will hold + * the directory entry. This requires the amount of space in struct dirent + * without the d_name field, plus enough space for the name with a terminating + * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary. + */ +#undef DIRSIZ +#ifdef notdef +#define DIRSIZ(dp) \ + ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) +#else +#define DIRSIZ(dp) \ + ((sizeof (struct dirent) - (MAXNAMLEN+1)) + ((strlen(dp->d_name)+1 + 3) &~ 3)) +#endif +int +scandir(dirname, namelist, select, dcomp) +#ifdef notdef + const char *dirname; +#else + char *dirname; +#endif + struct dirent ***namelist; +#ifdef notdef + int (*select) __P((struct dirent *)); + int (*dcomp) __P((const void *, const void *)); +#else + int (*select)(); + int (*dcomp)(); +#endif +{ + register struct dirent *d, *p, **names; + register size_t nitems; + struct stat stb; + long arraysz; + DIR *dirp; + if ((dirp = opendir(dirname)) == NULL) + return(-1); + if (stat(dirname, &stb) < 0) + return(-1); + /* + * estimate the array size by taking the size of the directory file + * and dividing it by a multiple of the minimum size entry. + */ + arraysz = (stb.st_size / 24); + names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *)); + if (names == NULL) + return(-1); + nitems = 0; + while ((d = readdir(dirp)) != NULL) { + if (select != NULL && !(*select)(d)) + continue; /* just selected names */ + /* + * Make a minimum size copy of the data + */ + p = (struct dirent *)malloc(DIRSIZ(d)); + if (p == NULL) + return(-1); + p->d_ino = d->d_ino; + p->d_reclen = d->d_reclen; +#ifdef notdef + p->d_namlen = d->d_namlen; + bcopy(d->d_name, p->d_name, p->d_namlen + 1); +#else + bcopy(d->d_name, p->d_name, strlen(p->d_name) + 1); +#endif + /* + * Check to make sure the array has space left and + * realloc the maximum size. + */ + if (++nitems >= arraysz) { + if (stat(dirname, &stb) < 0) + return(-1); /* just might have grown */ + arraysz = stb.st_size / 12; + names = (struct dirent **)realloc((char *)names, + arraysz * sizeof(struct dirent *)); + if (names == NULL) + return(-1); + } + names[nitems-1] = p; + } + closedir(dirp); + if (nitems && dcomp != NULL) + qsort(names, nitems, sizeof(struct dirent *), dcomp); + *namelist = names; + return(nitems); +} +/* + * Alphabetic order comparison routine for those who want it. + */ +int +alphasort(d1, d2) +#ifdef notdef + const void *d1; + const void *d2; +#else + char *d1; + char *d2; +#endif /* notdef */ +{ + return(strcmp((*(struct dirent **)d1)->d_name, + (*(struct dirent **)d2)->d_name)); +} +#endif