view uip/popi.c @ 10:a6481689f99c

*** empty log message ***
author kono
date Wed, 06 Dec 2006 03:17:53 +0900
parents bce86c4163a3
children 441a2190cfae
line wrap: on
line source

/* 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	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