Mercurial > hg > Applications > mh
diff uip/sbboards.c @ 0:bce86c4163a3
Initial revision
author | kono |
---|---|
date | Mon, 18 Apr 2005 23:46:02 +0900 |
parents | |
children | 441a2190cfae |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uip/sbboards.c Mon Apr 18 23:46:02 2005 +0900 @@ -0,0 +1,665 @@ +#ifndef SPOP +/* sbboards.c - MH style mailer to write to a ZOTnet BBoard */ +#else SPOP +/* spop.c - MH style mailer to write to a POP subscriber */ +#endif SPOP +#ifndef lint +static char ident[] = "@(#)$Id$"; +#endif lint + +#ifndef SPOP + +/* This program acts like the MMDF ch_bboards channel: it does local + delivery to a ZOTnet BBoard and/or addition re-distribution to other + recipients of the BBoard. This program can function both as a SendMail + mailer and an MH .mh_receive file, depending on whether SENDMTS or + MHMTS is set. Currently, the MHMTS version of this program does not do + re-distribution. + + This program should be used ONLY if you have "bboards on" set in your + MH configuration, and if you have "mts sendmail" or "mts mh" set as well. + */ + +#else SPOP + +/* This program acts like the MMDF-II ch_pop channel: it does local + delivery for non-local users. These users are known as POP subscribers + and use the Post Office Protocol with a POP server in order to access + their maildrop. + */ + +#endif SPOP + +#undef DISTRIBUTE +#ifdef SENDMTS +#ifndef SPOP +#define DISTRIBUTE +#endif not SPOP +#endif SENDMTS + +#include "../h/mh.h" +#ifndef SPOP +#include "../h/addrsbr.h" +#endif not SPOP +#include "../h/dropsbr.h" +#include "../zotnet/bboards.h" +#include "../zotnet/tws.h" +#include <stdio.h> +#include "../zotnet/mts.h" +#include <pwd.h> +#ifndef SYS5 +#include <sysexits.h> +#else SYS5 +#define EX_CANTCREAT 1 +#define EX_IOERR 1 +#define EX_NOINPUT 1 +#define EX_NOUSER 1 +#define EX_OK 0 +#define EX_OSERR 1 +#define EX_OSFILE 1 +#define EX_UNAVAILABLE 1 +#define EX_USAGE 1 +#endif SYS5 +#ifdef DISTRIBUTE +#include "../mts/sendmail/smail.h" +#endif DISTRIBUTE +#ifdef LOCALE +#include <locale.h> +#endif +#ifdef linux +#include <sys/types.h> +#endif +#if defined(UNISTD) && !defined(sgi) +#include <unistd.h> +#endif + +#define NBB 100 + +#ifndef SPOP +#define ENTITY "bboard" +#else SPOP +#define ENTITY "subscriber" +#endif SPOP + +/* */ + +static int bb_fderr; + +static int bb_uid; +static int bb_gid; + +static int dst_rcpt (); + + +#ifndef SPOP +static char bb_from[BUFSIZ]; +static char bb_head[BUFSIZ]; +static char bb_home[BUFSIZ]; +static char bb_time[BUFSIZ]; +#ifdef DISTRIBUTE +static char bb_rept[BUFSIZ]; +#endif DISTRIBUTE +#else SPOP +#define bb_head NULLCP +#endif SPOP + +static struct bboard *bb[NBB]; + +#if defined(UNISTD) && !defined(sgi) +#include <unistd.h> +#else +off_t lseek (); +#endif + +#ifndef __STDC__ +#ifdef SYS5 +struct passwd *getpwnam (); +#endif /* SYS5 */ +#endif + +#ifndef SPOP +static int mbx_init(); +#endif +#ifdef DISTRIBUTE +static int distribute(), notify(), encap(), + dst_init(), dst_text(), + dst_end(), dst_lose(), dst_adrs(); +#endif + +/* hack */ +#define adios my_adios +static localmail(), arginit(); +static int lose(), copyfile(); +static void adios(); +/* */ + +/* ARGSUSED */ + +main (argc, argv, envp) +int argc; +char **argv, + **envp; +{ + int fd; + char tmpfil[BUFSIZ]; + +#ifdef LOCALE + setlocale(LC_ALL, ""); +#endif +#ifdef JAPAN + ml_init(); +#endif /* JAPAN */ +#ifdef MHMTS + if (argc != 5) + adios (EX_USAGE, NULL, "you lose really big"); +#endif MHMTS + arginit (argv); + + fflush (stdout); + discard (stdout); /* XXX: reference discard to help loader */ + + fd = copyfile (fileno (stdin), tmpfil); + (void) unlink (tmpfil); + + localmail (fd); +#ifdef DISTRIBUTE + distribute (fd); + notify (fd); +#endif DISTRIBUTE + + exit (EX_OK); +} + +/* */ + +static localmail (fd) +int fd; +{ + int i, + md; + register struct bboard *bp; + + for (i = 0; bp = bb[i]; i++) + if (bp -> bb_file && *bp -> bb_file) { + (void) lseek (fd, (off_t)0, 0); +#ifndef SPOP + if ((md = mbx_open (bp -> bb_file, bb_uid, bb_gid, BBMODE)) +#else SPOP + if ((md = mbx_open (bp -> bb_file, bb_uid, bb_gid, POMODE)) +#endif SPOP + == NOTOK) { + (void) lose ("unable to open %s", bp -> bb_file); + continue; + } +#ifndef SPOP + if (mbx_init (bp) != NOTOK) +#endif not SPOP + (void) mbx_copy (bp -> bb_file, md, fd, 1, bb_head, 0); + (void) mbx_close (bp -> bb_file, md); + } +} + +/* */ + +#ifndef SPOP +static int mbx_init (bp) +register struct bboard *bp; +{ + int fd, + clear; + register struct bboard *ip; + register FILE *fp; + + if ((fd = mbx_Xopen (bp -> bb_info, bb_uid, bb_gid, BBMODE, &clear)) + == NOTOK) + return lose ("unable to lock and open %s", bp -> bb_info); + if ((fp = fdopen (fd, "w")) == NULL) { + (void) mbx_close (bp -> bb_info, fd); + return lose ("unable to fdopen %s", bp -> bb_info); + } + + if ((ip = getbbnam (bp -> bb_name)) == NULL) { + (void) lkfclose (fp, bp -> bb_info); + return lose ("unable to get information on BBoard %s", bp -> bb_name); + } + (void) strcpy (bb_time, dtimenow ()); + (void) sprintf (bb_head, "BBoard-ID: %d\nBB-Posted: %s\n", + bp -> bb_maxima = ++ip -> bb_maxima, bb_time); + + fprintf (fp, "%d\n%s\n", bp -> bb_maxima, bb_time); + (void) lkfclose (fp, bp -> bb_info); + + return OK; +} +#endif not SPOP + +/* */ + +#ifdef DISTRIBUTE +static distribute (fd) +int fd; +{ + int i; + register struct bboard *bp; + + for (i = 0; bp = bb[i]; i++) + if (bp -> bb_dist && *bp -> bb_dist) + break; + if (bp == NULL) + return; + + if (dst_init () == NOTOK) { + dst_lose (); + return; + } + for (i = 0; bp = bb[i]; i++) + if (bp -> bb_dist && *bp -> bb_dist) + if (dst_adrs (bp) == NOTOK) { + dst_lose (); + return; + } + if (dst_text (fd) == NOTOK || dst_end () == NOTOK) + dst_lose (); +} + +/* */ + +static int dst_init () +{ + int retval; + + if (rp_isbad (retval = sm_init (NULLCP, NULLCP, 0, 0, 0, 0, 0)) + || rp_isbad (retval = sm_winit (S_MAIL, bb_from))) + return lose ("problem initializing SendMail; %s", + rp_string (retval)); + + return OK; +} + +/* */ + +static int dst_adrs (bp) +register struct bboard *bp; +{ + if (getbbdist (bp, dst_rcpt)) + return lose ("getbbdist failed: %s", getbberr ()); + + return OK; +} + +/* */ + +static int dst_rcpt (mbox, host) +register char *mbox, + *host; +{ + int retval; + + switch (retval = sm_wadr (mbox, host, NULLCP)) { + case RP_OK: + return OK; + + case RP_NO: + case RP_USER: + (void) lose ("%s@%s: loses; %s", mbox, host, rp_string (retval)); + return OK; /* fail-soft */ + + default: + return lose ("%s@%s: unexpected response; %s", + mbox, host, rp_string (retval)); + } +} + +/* */ + +static int dst_text (fd) +int fd; +{ + int i, + retval; + char buffer[BUFSIZ]; + + if (rp_isbad (retval = sm_waend ())) + return lose ("problem ending addresses; %s", rp_string (retval)); + + (void) lseek (fd, (off_t)0, 0); + while ((i = read (fd, buffer, sizeof buffer)) > 0) + if (rp_isbad (retval = sm_wtxt (buffer, i))) + return lose ("problem writing text; %s", rp_string (retval)); + + return (i != NOTOK ? OK : lose ("error reading from file")); +} + +/* */ + +static int dst_end () +{ + int retval; + + switch (retval = sm_wtend ()) { + case RP_OK: + (void) sm_end (OK); + return OK; + + case RP_NO: + case RP_NDEL: + return lose ("posting failed; %s", rp_string (retval)); + + default: + return lose ("unexpected response; %s", rp_string (retval)); + } +} + +/* */ + +static dst_lose () +{ + (void) sm_end (NOTOK); +} + +/* */ + +/* VARARGS1 */ + +static int lose (fmt, a, b, c, d) +char *fmt, + *a, + *b, + *c, + *d; +{ + int fd, + i; + char *bp, + buffer[BUFSIZ]; + + if (bb_fderr == NOTOK) { + if ((fd = open ("/dev/null", 0)) == NOTOK) + adios (EX_OSERR, "/dev/null", "unable to open"); + bb_fderr = copyfile (fd, bb_rept); + } + + (void) sprintf (bp = buffer, fmt, a, b, c, d); + bp += strlen (bp); + bp += strlen (strcpy(bp, "\n")); + i = bp - buffer; + if (write (bb_fderr, buffer, i) != i) + adios (EX_IOERR, bb_rept, "error writing"); + + return NOTOK; +} + +/* */ + +static notify (fd) +int fd; +{ + int i; + char buffer[BUFSIZ]; + + if (bb_fderr == NOTOK) + return; + + if (rp_isbad (sm_init (NULLCP, NULLCP, 0, 0, 0, 0, 0)) + || rp_isbad (sm_winit (S_MAIL, bb_from))) + goto sm_err; + + switch (sm_wadr (bb_from, NULLCP, NULLCP)) { + case RP_OK: + for (i = 0; bb[i]; i++) { + (void) sprintf (buffer, "local-%s-request", bb[i] -> bb_name); + (void) sm_wadr (buffer, LocalName (), NULLCP); + } + break; + + default: + goto sm_err; + } + + if (rp_isbad (sm_waend ())) + goto sm_err; + + (void) sprintf (buffer, + "Date: %s\nFrom: %s\nTo: %s\nSubject: BBoards Failure\n\n", + dtimenow (), bb_from, bb_from); + if (rp_isbad (sm_wtxt (buffer, strlen (buffer)))) + goto sm_err; + + for (i = 0; bb[i]; i++) { + (void) sprintf (buffer, "BBoard %s\n", bb[i] -> bb_name); + if (rp_isbad (sm_wtxt (buffer, strlen (buffer)))) + goto sm_err; + } + + (void) lseek (bb_fderr, (off_t)0, 0); + while ((i = read (bb_fderr, buffer, sizeof buffer)) > 0) + if (rp_isbad (sm_wtxt (buffer, i))) + goto sm_err; + + (void) strcpy (buffer, "\n------- Forwarded Message\n\n"); + if (rp_isbad (sm_wtxt (buffer, strlen (buffer))) || encap (fd) == NOTOK) + goto sm_err; + (void) strcpy (buffer, "\n------- End of Forwarded Message\n\n"); + if (rp_isbad (sm_wtxt (buffer, strlen (buffer)))) + goto sm_err; + + switch (sm_wtend ()) { + case RP_OK: + (void) unlink (bb_rept); + (void) sm_end (OK); + return; + + default: + sm_err: ; + adios (EX_UNAVAILABLE, NULLCP, + "failed and unable to post advisory, see %s for details", + bb_rept); + } +} + +/* */ + +/* very similar to sbr/cpydgst.c */ + +#define S1 0 +#define S2 1 + +#define output(c) if (bp >= dp) flush (), *bp++ = c; else *bp++ = c +#define flush() if ((j = bp - outbuf) \ + && rp_isbad (sm_wtxt (outbuf, j))) \ + return NOTOK; \ + else \ + bp = outbuf + +static int encap (fd) +register int fd; +{ + register int i, + state; + register char *cp, + *ep; + char buffer[BUFSIZ]; + register int j; + register char *bp, + *dp; + char outbuf[BUFSIZ]; + + (void) lseek (fd, (off_t)0, 0); + + dp = (bp = outbuf) + sizeof outbuf; + for (state = S1; (i = read (fd, buffer, sizeof buffer)) > 0;) + for (ep = (cp = buffer) + i; cp < ep; cp++) { + if (*cp == '\0') + continue; + switch (state) { + case S1: + if (*cp == '-') { + output ('-'); + output (' '); + } + state = S2; /* fall */ + + case S2: + output (*cp); + if (*cp == '\n') + state = S1; + break; + } + } + + if (i == NOTOK) + return NOTOK; + flush (); + + return OK; +} +#endif DISTRIBUTE + +/* */ + +#ifndef DISTRIBUTE +/* VARARGS1 */ + +static int lose (fmt, a, b, c, d) +char *fmt, + *a, + *b, + *c, + *d; +{ + adios (EX_UNAVAILABLE, NULLCP, fmt, a, b, c, d);/* NOTREACHED */ +} +#endif not DISTRIBUTE + +/* */ + +static arginit (vec) +register char **vec; +{ + register int i; +#ifdef MHMTS + register char *ap; +#endif MHMTS + char addr[BUFSIZ]; + register struct bboard *bp; + register struct passwd *pw; + + invo_name = r1bindex (*vec++, '/'); + if (strlen(invo_name) > NAMESZ) { + fprintf(stderr, "%s: argv[0] too long\n", invo_name); + exit(1); + } + m_foil (NULLCP); + mts_init (invo_name); + +#ifndef SPOP + if ((pw = getpwnam (BBOARDS)) == NULL) + adios (EX_OSFILE, NULLCP, "no entry for ~%s", BBOARDS); +#else SPOP + if ((pw = getpwnam (POPUID)) == NULL || !setpwinfo (pw, POPDB, 1)) + adios (EX_OSFILE, NULLCP, "%s", pw ? getbberr () : "POP user-id unknown"); +#endif SPOP + + if (pw -> pw_uid != geteuid ()) +#ifndef SPOP + adios (EX_OSERR, NULLCP, "not running setuid to %s", BBOARDS); +#else SPOP + adios (EX_OSERR, NULLCP, "not running setuid to %s", POPUID); +#endif SPOP + + bb_uid = pw -> pw_uid; + bb_gid = pw -> pw_gid; +#ifndef SPOP + (void) strcpy (bb_from, adrsprintf (pw -> pw_name, LocalName ())); + (void) strcpy (bb_home, pw -> pw_dir); +#endif not SPOP + +#ifdef MHMTS + vec += 3; +#endif MHMTS + if (*vec == NULL) + adios (EX_USAGE, NULLCP, "usage: %s %s [%s ...]", + invo_name, ENTITY, ENTITY); + + for (i = 0; *vec; vec++) { + if (strlen(*vec) >= BUFSIZ / 4) + adios (NULLCP, "argument too long"); +#ifdef MHMTS + if (ap = index (*vec, '.')) + *vec = ++ap; +#endif MHMTS + make_lower (addr, *vec); + + if ((bp = getbbnam (addr)) == NULL + && (bp = getbbaka (addr)) == NULL) + adios (EX_NOUSER, NULLCP, "no such %s as %s", ENTITY, *vec); + if ((bb[i++] = getbbcpy (bp)) == NULL) + adios (EX_UNAVAILABLE, NULLCP, "insufficient memory on %s", *vec); + + if (i >= NBB - 1) + adios (EX_USAGE, NULLCP, "too many %ss, starting with %s", + ENTITY, *vec); + } + bb[i] = NULL; + + (void) umask (0022); + + bb_fderr = NOTOK; +} + +/* */ + +static int copyfile (qd, tmpfil) +int qd; +register char *tmpfil; +{ + int i, + fd; + char buffer[BUFSIZ]; + + (void) strcpy (tmpfil, m_tmpfil (invo_name)); + if ((fd = creat (tmpfil, 0600)) == NOTOK) + adios (EX_CANTCREAT, tmpfil, "unable to create"); + (void) close (fd); + if ((fd = open (tmpfil, 2)) == NOTOK) + adios (EX_NOINPUT, tmpfil, "unable to re-open"); + + (void) lseek (qd, (off_t)0, 0); + while ((i = read (qd, buffer, sizeof buffer)) > 0) + if (write (fd, buffer, i) != i) + adios (EX_IOERR, tmpfil, "error writing"); + if (i == NOTOK) + adios (EX_IOERR, "input", "error reading"); + + (void) lseek (fd, (off_t)0, 0); + + return fd; +} + +/* */ + +/* VARARGS3 */ + +#ifdef MHMTS +/* ARGSUSED */ +#endif MHMTS + +static void adios (code, what, fmt, a, b, c, d, e, f) +int code; +char *what, + *fmt, + *a, + *b, + *c, + *d, + *e, + *f; +{ + advise (what, fmt, a, b, c, d, e, f); +#ifdef SENDMTS + done (code); +#endif SENDMTS +#ifdef MHMTS + done (1); +#endif MHMTS +}