1: #ifndef SPOP 2: /* sbboards.c - MH style mailer to write to a ZOTnet BBoard */ 3: #else SPOP 4: /* spop.c - MH style mailer to write to a POP subscriber */ 5: #endif SPOP 6: 7: #ifndef SPOP 8: 9: /* This program acts like the MMDF ch_bboards channel: it does local 10: delivery to a ZOTnet BBoard and/or addition re-distribution to other 11: recipients of the BBoard. This program can function both as a SendMail 12: mailer and an MH .mh_receive file, depending on whether SENDMTS or 13: MHMTS is set. Currently, the MHMTS version of this program does not do 14: re-distribution. 15: 16: This program should be used ONLY if you have "bboards on" set in your 17: MH configuration, and if you have "mts sendmail" or "mts mh" set as well. 18: */ 19: 20: #else SPOP 21: 22: /* This program acts like the MMDF-II ch_pop channel: it does local 23: delivery for non-local users. These users are known as POP subscribers 24: and use the Post Office Protocol with a POP server in order to access 25: their maildrop. 26: */ 27: 28: #endif SPOP 29: 30: #undef DISTRIBUTE 31: #ifdef SENDMTS 32: #ifndef SPOP 33: #define DISTRIBUTE 34: #endif not SPOP 35: #endif SENDMTS 36: 37: #include "../h/mh.h" 38: #ifndef SPOP 39: #include "../h/addrsbr.h" 40: #endif not SPOP 41: #include "../h/dropsbr.h" 42: #include "../zotnet/bboards.h" 43: #include "../zotnet/tws.h" 44: #include <stdio.h> 45: #include "../zotnet/mts.h" 46: #include <pwd.h> 47: #ifndef SYS5 48: #include <sysexits.h> 49: #else SYS5 50: #define EX_CANTCREAT 1 51: #define EX_IOERR 1 52: #define EX_NOINPUT 1 53: #define EX_NOUSER 1 54: #define EX_OK 0 55: #define EX_OSERR 1 56: #define EX_OSFILE 1 57: #define EX_UNAVAILABLE 1 58: #define EX_USAGE 1 59: #endif SYS5 60: #ifdef DISTRIBUTE 61: #include "../mts/sendmail/smail.h" 62: #endif DISTRIBUTE 63: 64: 65: #define NBB 100 66: 67: #ifndef SPOP 68: #define ENTITY "bboard" 69: #else SPOP 70: #define ENTITY "subscriber" 71: #endif SPOP 72: 73: /* */ 74: 75: static int bb_fderr; 76: 77: static int bb_uid; 78: static int bb_gid; 79: 80: int dst_rcpt (); 81: 82: 83: #ifndef SPOP 84: static char bb_from[BUFSIZ]; 85: static char bb_head[BUFSIZ]; 86: static char bb_home[BUFSIZ]; 87: static char bb_time[BUFSIZ]; 88: #ifdef DISTRIBUTE 89: static char bb_rept[BUFSIZ]; 90: #endif DISTRIBUTE 91: #else SPOP 92: #define bb_head NULLCP 93: #endif SPOP 94: 95: static struct bboard *bb[NBB]; 96: 97: 98: long lseek (); 99: 100: #ifdef SYS5 101: struct passwd *getpwnam (); 102: #endif SYS5 103: 104: /* */ 105: 106: /* ARGSUSED */ 107: 108: main (argc, argv, envp) 109: int argc; 110: char **argv, 111: **envp; 112: { 113: int fd; 114: char tmpfil[BUFSIZ]; 115: 116: #ifdef MHMTS 117: if (argc != 5) 118: adios (EX_USAGE, NULL, "you lose really big"); 119: #endif MHMTS 120: arginit (argv); 121: 122: fd = copyfile (fileno (stdin), tmpfil); 123: (void) unlink (tmpfil); 124: 125: localmail (fd); 126: #ifdef DISTRIBUTE 127: distribute (fd); 128: notify (fd); 129: #endif DISTRIBUTE 130: 131: exit (EX_OK); 132: } 133: 134: /* */ 135: 136: static localmail (fd) 137: int fd; 138: { 139: int i, 140: md; 141: register struct bboard *bp; 142: 143: for (i = 0; bp = bb[i]; i++) 144: if (bp -> bb_file && *bp -> bb_file) { 145: (void) lseek (fd, 0L, 0); 146: #ifndef SPOP 147: if ((md = mbx_open (bp -> bb_file, bb_uid, bb_gid, BBMODE)) 148: #else SPOP 149: if ((md = mbx_open (bp -> bb_file, bb_uid, bb_gid, POMODE)) 150: #endif SPOP 151: == NOTOK) { 152: (void) lose ("unable to open %s", bp -> bb_file); 153: continue; 154: } 155: #ifndef SPOP 156: if (mbx_init (bp) != NOTOK) 157: #endif not SPOP 158: (void) mbx_copy (bp -> bb_file, md, fd, 1, bb_head, 0); 159: (void) mbx_close (bp -> bb_file, md); 160: } 161: } 162: 163: /* */ 164: 165: #ifndef SPOP 166: static int mbx_init (bp) 167: register struct bboard *bp; 168: { 169: int fd, 170: clear; 171: register struct bboard *ip; 172: register FILE *fp; 173: 174: if ((fd = mbx_Xopen (bp -> bb_info, bb_uid, bb_gid, BBMODE, &clear)) 175: == NOTOK) 176: return lose ("unable to lock and open %s", bp -> bb_info); 177: if ((fp = fdopen (fd, "w")) == NULL) { 178: (void) mbx_close (bp -> bb_info, fd); 179: return lose ("unable to fdopen %s", bp -> bb_info); 180: } 181: 182: if ((ip = getbbnam (bp -> bb_name)) == NULL) { 183: (void) lkfclose (fp, bp -> bb_info); 184: return lose ("unable to get information on BBoard %s", bp -> bb_name); 185: } 186: (void) strcpy (bb_time, dtimenow ()); 187: (void) sprintf (bb_head, "BBoard-ID: %d\nBB-Posted: %s\n", 188: bp -> bb_maxima = ++ip -> bb_maxima, bb_time); 189: 190: fprintf (fp, "%d\n%s\n", bp -> bb_maxima, bb_time); 191: (void) lkfclose (fp, bp -> bb_info); 192: 193: return OK; 194: } 195: #endif not SPOP 196: 197: /* */ 198: 199: #ifdef DISTRIBUTE 200: static distribute (fd) 201: int fd; 202: { 203: int i; 204: register struct bboard *bp; 205: 206: for (i = 0; bp = bb[i]; i++) 207: if (bp -> bb_dist && *bp -> bb_dist) 208: break; 209: if (bp == NULL) 210: return; 211: 212: if (dst_init () == NOTOK) { 213: dst_lose (); 214: return; 215: } 216: for (i = 0; bp = bb[i]; i++) 217: if (bp -> bb_dist && *bp -> bb_dist) 218: if (dst_adrs (bp) == NOTOK) { 219: dst_lose (); 220: return; 221: } 222: if (dst_text (fd) == NOTOK || dst_end () == NOTOK) 223: dst_lose (); 224: } 225: 226: /* */ 227: 228: static int dst_init () 229: { 230: int retval; 231: 232: if (rp_isbad (retval = sm_init (NULLCP, NULLCP, 0, 0, 0)) 233: || rp_isbad (retval = sm_winit (S_MAIL, bb_from))) 234: return lose ("problem initializing SendMail; %s", 235: rp_string (retval)); 236: 237: return OK; 238: } 239: 240: /* */ 241: 242: static int dst_adrs (bp) 243: register struct bboard *bp; 244: { 245: if (getbbdist (bp, dst_rcpt)) 246: return lose ("getbbdist failed: %s", getbberr ()); 247: 248: return OK; 249: } 250: 251: /* */ 252: 253: static int dst_rcpt (mbox, host) 254: register char *mbox, 255: *host; 256: { 257: int retval; 258: 259: switch (retval = sm_wadr (mbox, host, NULLCP)) { 260: case RP_OK: 261: return OK; 262: 263: case RP_NO: 264: case RP_USER: 265: (void) lose ("%s@%s: loses; %s", mbox, host, rp_string (retval)); 266: return OK; /* fail-soft */ 267: 268: default: 269: return lose ("%s@%s: unexpected response; %s", 270: mbox, host, rp_string (retval)); 271: } 272: } 273: 274: /* */ 275: 276: static int dst_text (fd) 277: int fd; 278: { 279: int i, 280: retval; 281: char buffer[BUFSIZ]; 282: 283: if (rp_isbad (retval = sm_waend ())) 284: return lose ("problem ending addresses; %s", rp_string (retval)); 285: 286: (void) lseek (fd, 0L, 0); 287: while ((i = read (fd, buffer, sizeof buffer)) > 0) 288: if (rp_isbad (retval = sm_wtxt (buffer, i))) 289: return lose ("problem writing text; %s", rp_string (retval)); 290: 291: return (i != NOTOK ? OK : lose ("error reading from file")); 292: } 293: 294: /* */ 295: 296: static int dst_end () 297: { 298: int retval; 299: 300: switch (retval = sm_wtend ()) { 301: case RP_OK: 302: (void) sm_end (OK); 303: return OK; 304: 305: case RP_NO: 306: case RP_NDEL: 307: return lose ("posting failed; %s", rp_string (retval)); 308: 309: default: 310: return lose ("unexpected response; %s", rp_string (retval)); 311: } 312: } 313: 314: /* */ 315: 316: static dst_lose () 317: { 318: (void) sm_end (NOTOK); 319: } 320: 321: /* */ 322: 323: /* VARARGS1 */ 324: 325: static int lose (fmt, a, b, c, d) 326: char *fmt, 327: *a, 328: *b, 329: *c, 330: *d; 331: { 332: int fd, 333: i; 334: char *bp, 335: buffer[BUFSIZ]; 336: 337: if (bb_fderr == NOTOK) { 338: if ((fd = open ("/dev/null", 0)) == NOTOK) 339: adios (EX_OSERR, "/dev/null", "unable to open"); 340: bb_fderr = copyfile (fd, bb_rept); 341: } 342: 343: (void) sprintf (bp = buffer, fmt, a, b, c, d); 344: bp += strlen (bp); 345: bp += strlen (strcpy(bp, "\n")); 346: i = bp - buffer; 347: if (write (bb_fderr, buffer, i) != i) 348: adios (EX_IOERR, bb_rept, "error writing"); 349: 350: return NOTOK; 351: } 352: 353: /* */ 354: 355: static notify (fd) 356: int fd; 357: { 358: int i; 359: char buffer[BUFSIZ]; 360: 361: if (bb_fderr == NOTOK) 362: return; 363: 364: if (rp_isbad (sm_init (NULLCP, NULLCP, 0, 0, 0)) 365: || rp_isbad (sm_winit (S_MAIL, bb_from))) 366: goto sm_err; 367: 368: switch (sm_wadr (bb_from, NULLCP, NULLCP)) { 369: case RP_OK: 370: for (i = 0; bb[i]; i++) { 371: (void) sprintf (buffer, "local-%s-request", bb[i] -> bb_name); 372: (void) sm_wadr (buffer, LocalName (), NULLCP); 373: } 374: break; 375: 376: default: 377: goto sm_err; 378: } 379: 380: if (rp_isbad (sm_waend ())) 381: goto sm_err; 382: 383: (void) sprintf (buffer, 384: "Date: %s\nFrom: %s\nTo: %s\nSubject: BBoards Failure\n\n", 385: dtimenow (), bb_from, bb_from); 386: if (rp_isbad (sm_wtxt (buffer, strlen (buffer)))) 387: goto sm_err; 388: 389: for (i = 0; bb[i]; i++) { 390: (void) sprintf (buffer, "BBoard %s\n", bb[i] -> bb_name); 391: if (rp_isbad (sm_wtxt (buffer, strlen (buffer)))) 392: goto sm_err; 393: } 394: 395: (void) lseek (bb_fderr, 0L, 0); 396: while ((i = read (bb_fderr, buffer, sizeof buffer)) > 0) 397: if (rp_isbad (sm_wtxt (buffer, i))) 398: goto sm_err; 399: 400: (void) strcpy (buffer, "\n------- Forwarded Message\n\n"); 401: if (rp_isbad (sm_wtxt (buffer, strlen (buffer))) || encap (fd) == NOTOK) 402: goto sm_err; 403: (void) strcpy (buffer, "\n------- End of Forwarded Message\n\n"); 404: if (rp_isbad (sm_wtxt (buffer, strlen (buffer)))) 405: goto sm_err; 406: 407: switch (sm_wtend ()) { 408: case RP_OK: 409: (void) unlink (bb_rept); 410: (void) sm_end (OK); 411: return; 412: 413: default: 414: sm_err: ; 415: adios (EX_UNAVAILABLE, NULLCP, 416: "failed and unable to post advisory, see %s for details", 417: bb_rept); 418: } 419: } 420: 421: /* */ 422: 423: /* very similar to sbr/cpydgst.c */ 424: 425: #define S1 0 426: #define S2 1 427: 428: #define output(c) if (bp >= dp) flush (), *bp++ = c; else *bp++ = c 429: #define flush() if ((j = bp - outbuf) \ 430: && rp_isbad (sm_wtxt (outbuf, j))) \ 431: return NOTOK; \ 432: else \ 433: bp = outbuf 434: 435: static int encap (fd) 436: register int fd; 437: { 438: register int i, 439: state; 440: register char *cp, 441: *ep; 442: char buffer[BUFSIZ]; 443: register int j; 444: register char *bp, 445: *dp; 446: char outbuf[BUFSIZ]; 447: 448: (void) lseek (fd, 0L, 0); 449: 450: dp = (bp = outbuf) + sizeof outbuf; 451: for (state = S1; (i = read (fd, buffer, sizeof buffer)) > 0;) 452: for (ep = (cp = buffer) + i; cp < ep; cp++) { 453: if (*cp == NULL) 454: continue; 455: switch (state) { 456: case S1: 457: if (*cp == '-') { 458: output ('-'); 459: output (' '); 460: } 461: state = S2; /* fall */ 462: 463: case S2: 464: output (*cp); 465: if (*cp == '\n') 466: state = S1; 467: break; 468: } 469: } 470: 471: if (i == NOTOK) 472: return NOTOK; 473: flush (); 474: 475: return OK; 476: } 477: #endif DISTRIBUTE 478: 479: /* */ 480: 481: #ifndef DISTRIBUTE 482: /* VARARGS1 */ 483: 484: static int lose (fmt, a, b, c, d) 485: char *fmt, 486: *a, 487: *b, 488: *c, 489: *d; 490: { 491: adios (EX_UNAVAILABLE, NULLCP, fmt, a, b, c, d);/* NOTREACHED */ 492: } 493: #endif not DISTRIBUTE 494: 495: /* */ 496: 497: static arginit (vec) 498: register char **vec; 499: { 500: register int i; 501: #ifdef MHMTS 502: register char *ap; 503: #endif MHMTS 504: char addr[BUFSIZ]; 505: register struct bboard *bp; 506: register struct passwd *pw; 507: 508: invo_name = r1bindex (*vec++, '/'); 509: m_foil (NULLCP); 510: mts_init (invo_name); 511: 512: #ifndef SPOP 513: if ((pw = getpwnam (BBOARDS)) == NULL) 514: adios (EX_OSFILE, NULLCP, "no entry for ~%s", BBOARDS); 515: #else SPOP 516: if ((pw = getpwnam (POPUID)) == NULL || !setpwinfo (pw, POPDB, 1)) 517: adios (EX_OSFILE, NULLCP, "%s", pw ? getbberr () : "POP user-id unknown"); 518: #endif SPOP 519: 520: if (pw -> pw_uid != geteuid ()) 521: #ifndef SPOP 522: adios (EX_OSERR, NULLCP, "not running setuid to %s", BBOARDS); 523: #else SPOP 524: adios (EX_OSERR, NULLCP, "not running setuid to %s", POPUID); 525: #endif SPOP 526: 527: bb_uid = pw -> pw_uid; 528: bb_gid = pw -> pw_gid; 529: #ifndef SPOP 530: (void) strcpy (bb_from, adrsprintf (pw -> pw_name, LocalName ())); 531: (void) strcpy (bb_home, pw -> pw_dir); 532: #endif not SPOP 533: 534: #ifdef MHMTS 535: vec += 3; 536: #endif MHMTS 537: if (*vec == NULL) 538: adios (EX_USAGE, NULLCP, "usage: %s %s [%s ...]", 539: invo_name, ENTITY, ENTITY); 540: 541: for (i = 0; *vec; vec++) { 542: #ifdef MHMTS 543: if (ap = index (*vec, '.')) 544: *vec = ++ap; 545: #endif MHMTS 546: make_lower (addr, *vec); 547: 548: if ((bp = getbbnam (addr)) == NULL 549: && (bp = getbbaka (addr)) == NULL) 550: adios (EX_NOUSER, NULLCP, "no such %s as %s", ENTITY, *vec); 551: if ((bb[i++] = getbbcpy (bp)) == NULL) 552: adios (EX_UNAVAILABLE, NULLCP, "insufficient memory on %s", *vec); 553: 554: if (i >= NBB - 1) 555: adios (EX_USAGE, NULLCP, "too many %ss, starting with %s", 556: ENTITY, *vec); 557: } 558: bb[i] = NULL; 559: 560: (void) umask (0022); 561: 562: bb_fderr = NOTOK; 563: } 564: 565: /* */ 566: 567: static int copyfile (qd, tmpfil) 568: int qd; 569: register char *tmpfil; 570: { 571: int i, 572: fd; 573: char buffer[BUFSIZ]; 574: 575: (void) strcpy (tmpfil, m_tmpfil (invo_name)); 576: if ((fd = creat (tmpfil, 0600)) == NOTOK) 577: adios (EX_CANTCREAT, tmpfil, "unable to create"); 578: (void) close (fd); 579: if ((fd = open (tmpfil, 2)) == NOTOK) 580: adios (EX_NOINPUT, tmpfil, "unable to re-open"); 581: 582: (void) lseek (qd, 0L, 0); 583: while ((i = read (qd, buffer, sizeof buffer)) > 0) 584: if (write (fd, buffer, i) != i) 585: adios (EX_IOERR, tmpfil, "error writing"); 586: if (i == NOTOK) 587: adios (EX_IOERR, "input", "error reading"); 588: 589: (void) lseek (fd, 0L, 0); 590: 591: return fd; 592: } 593: 594: /* */ 595: 596: /* VARARGS3 */ 597: 598: #ifdef MHMTS 599: /* ARGSUSED */ 600: #endif MHMTS 601: 602: static void adios (code, what, fmt, a, b, c, d, e, f) 603: int code; 604: char *what, 605: *fmt, 606: *a, 607: *b, 608: *c, 609: *d, 610: *e, 611: *f; 612: { 613: advise (what, fmt, a, b, c, d, e, f); 614: #ifdef SENDMTS 615: done (code); 616: #endif SENDMTS 617: #ifdef MHMTS 618: done (1); 619: #endif MHMTS 620: }