1: /* popser.c - the POP service */ 2: 3: #include "../h/mh.h" 4: #include "../h/dropsbr.h" 5: #include "../zotnet/bboards.h" 6: #include <stdio.h> 7: #include "../zotnet/mts.h" 8: #include <ctype.h> 9: #include <errno.h> 10: #include <pwd.h> 11: #include <signal.h> 12: #include <syslog.h> 13: #include <sys/types.h> 14: #include <sys/stat.h> 15: 16: 17: #define TRUE 1 18: #define FALSE 0 19: 20: #define NVEC 4 21: 22: /* */ 23: 24: extern int errno; 25: 26: extern int debug; 27: extern char myhost[]; 28: extern char *myname; 29: 30: static enum state { 31: auth1, auth2, trans, update, halt, error 32: } mystate; 33: 34: 35: int user (), pass (); 36: #ifdef RPOP 37: int rpop (); 38: #endif RPOP 39: int status (), list (), retrieve (), delete (), reset (); 40: int top (); 41: #ifdef BPOP 42: int xtnd (); 43: #endif BPOP 44: int quit (); 45: 46: static struct vector { 47: char *v_cmd; 48: int v_min, v_max; 49: int (*v_vec) (); 50: enum state v_valid; 51: enum state v_win, v_lose; 52: } vectors[] = { 53: "user", 1, 1, user, auth1, auth2, auth1, 54: "pass", 1, 1, pass, auth2, trans, auth1, 55: #ifdef RPOP 56: "rpop", 1, 1, rpop, auth2, trans, auth1, 57: #endif RPOP 58: "quit", 0, 0, NULL, auth1, halt, halt, 59: "quit", 0, 0, NULL, auth2, halt, halt, 60: 61: "stat", 0, 0, status, trans, trans, trans, 62: "list", 0, 1, list, trans, trans, trans, 63: "retr", 1, 1, retrieve, trans, trans, trans, 64: "dele", 1, 1, delete, trans, trans, trans, 65: "noop", 0, 0, NULL, trans, trans, trans, 66: "rset", 0, 0, reset, trans, trans, trans, 67: 68: "top", 2, 2, top, trans, trans, trans, 69: #ifdef BPOP 70: "xtnd", 1, 2, xtnd, trans, trans, trans, 71: #endif BPOP 72: 73: "quit", 0, 0, quit, trans, halt, halt, 74: 75: NULL 76: }; 77: 78: struct vector *getvector (); 79: 80: /* */ 81: 82: #ifdef DPOP 83: static int pop_uid; 84: static int pop_gid; 85: #endif DPOP 86: 87: static int rproto; 88: static char *hostname; 89: static char server[BUFSIZ]; 90: 91: static char username[BUFSIZ]; 92: 93: static char maildrop[BUFSIZ]; 94: static int mode; 95: static time_t mtime; 96: static FILE *dp; 97: 98: #ifdef BPOP 99: static int xtnded; 100: 101: static int guest_uid; 102: static int guest_gid; 103: 104: static struct bboard *BBhead = NULL; 105: static struct bboard *BBtail = NULL; 106: 107: static long BBtime = 0L; 108: 109: struct bboard *getbbaux (); 110: #endif BPOP 111: 112: 113: struct Msg { /* Msgs[0] contains info for entire maildrop */ 114: struct drop m_drop; 115: #define m_id m_drop.d_id 116: #define m_size m_drop.d_size 117: #define m_start m_drop.d_start 118: #define m_stop m_drop.d_stop 119: 120: unsigned m_flags; 121: #define MNULL 0x00 122: #define MDELE 0x01 123: #define MREAD 0x02 124: }; 125: 126: static int nMsgs = 0; 127: static struct Msg *Msgs = NULL; 128: 129: static int nmsgs; 130: static int dmsgs; 131: 132: 133: #define TRM "." 134: #define TRMLEN (sizeof TRM - 1) 135: #define IAC 255 136: 137: int pipeser (); 138: 139: FILE *input; 140: FILE *output; 141: 142: 143: void padvise (), padios (); 144: long lseek (); 145: char *crypt (); 146: 147: /* */ 148: 149: popinit () { 150: #ifdef BPOP 151: padvise (NULLCP, LOG_INFO, "initialize list of BBoards"); 152: 153: BBhead = BBtail = NULL; 154: while (getbbaux (NULLCP)) 155: continue; 156: #endif BPOP 157: } 158: 159: popassert () { 160: #ifdef BPOP 161: register char **p; 162: register struct bboard *bb, 163: *bp; 164: 165: if (BBtime == getbbtime ()) 166: return; 167: 168: padvise (NULLCP, LOG_INFO, "list of BBoards has changed"); 169: 170: for (bb = BBhead; bb; bb = bp) { 171: bp = bb -> bb_next; 172: 173: if (bb -> bb_name) 174: free (bb -> bb_name); 175: if (bb -> bb_file) 176: free (bb -> bb_file); 177: if (bb -> bb_archive) 178: free (bb -> bb_archive); 179: if (bb -> bb_info) 180: free (bb -> bb_info); 181: if (bb -> bb_map) 182: free (bb -> bb_map); 183: if (bb -> bb_passwd) 184: free (bb -> bb_passwd); 185: if (bb -> bb_date) 186: free (bb -> bb_date); 187: if (bb -> bb_addr) 188: free (bb -> bb_addr); 189: if (bb -> bb_request) 190: free (bb -> bb_request); 191: if (bb -> bb_relay) 192: free (bb -> bb_relay); 193: 194: for (p = bb -> bb_aka; *p; p++) 195: free (*p); 196: free ((char *) bb -> bb_aka); 197: 198: for (p = bb -> bb_leader; *p; p++) 199: free (*p); 200: free ((char *) bb -> bb_leader); 201: 202: for (p = bb -> bb_dist; *p; p++) 203: free (*p); 204: free ((char *) bb -> bb_dist); 205: 206: free ((char *) bb); 207: } 208: 209: BBhead = BBtail = NULL; 210: while (getbbaux (NULLCP)) 211: continue; 212: #endif BPOP 213: } 214: 215: /* */ 216: 217: pop (in, out, priv, rhost) 218: int in, 219: out, 220: priv; 221: char *rhost; 222: { 223: char buffer[BUFSIZ], 224: *vec[NVEC + 1]; 225: #if defined (DPOP) || defined (BPOP) 226: register struct passwd *pw; 227: #endif defined (DPOP) || defined (BPOP) 228: register struct vector *v; 229: 230: m_foil (NULLCP); 231: mts_init (myname); 232: 233: rproto = priv; 234: hostname = rhost; 235: (void) sprintf (server, "%s %s server", myhost, priv ? "RPOP" : "POP"); 236: 237: if ((input = fdopen (in, "r")) == NULL 238: || (output = fdopen (out, "w")) == NULL) {/* you lose big */ 239: (void) respond (NOTOK, "%s loses on initialization", server); 240: return; 241: } 242: (void) signal (SIGPIPE, pipeser); 243: 244: #ifdef DPOP 245: if ((pw = getpwnam (POPUID)) == NULL || !setpwinfo (pw, POPDB, 1)) { 246: (void) respond (NOTOK, "%s loses on DB initialization -- %s", 247: server, pw ? getbberr () : "POP user-id unknown"); 248: return; 249: } 250: pop_uid = pw -> pw_uid; 251: pop_gid = pw -> pw_gid; 252: #endif DPOP 253: #ifdef BPOP 254: if ((pw = getpwnam (popbbuser)) && pw -> pw_uid) { 255: guest_uid = pw -> pw_uid; 256: guest_gid = pw -> pw_gid; 257: } 258: else 259: guest_uid = guest_gid = 0; 260: #endif BPOP 261: 262: (void) respond (OK, "%s ready (Comments to: PostMaster@%s)", 263: server, myhost); 264: 265: for (mystate = auth1; mystate != halt && mystate != error;) 266: switch (getline (buffer, sizeof buffer, input)) { 267: case OK: 268: if ((v = getvector (buffer, vec)) == NULL) 269: continue; 270: mystate = (v -> v_vec ? (v -> v_vec) (vec) 271: : respond (OK, NULLCP)) == OK 272: ? v -> v_win 273: : v -> v_lose; 274: break; 275: 276: case NOTOK: 277: case DONE: 278: mystate = error; 279: (void) respond (NOTOK, "%s signing off", server); 280: break; 281: } 282: } 283: 284: /* */ 285: 286: static int user (vec) 287: register char **vec; 288: { 289: make_lower (username, vec[1]); 290: 291: return respond (OK, "password required for %s", username); 292: } 293: 294: /* */ 295: 296: static int pass (vec) 297: register char **vec; 298: { 299: int guest = 0; 300: #ifndef DPOP 301: register struct passwd *pw; 302: #else DPOP 303: register struct bboard *pw; 304: #endif DPOP 305: 306: #ifndef DPOP 307: #ifdef BPOP 308: if (isguest ()) { 309: #ifdef TRUSTED 310: static passwd gw; 311: 312: gw.pw_name = popbbuser; 313: gw.pw_uid = guest_uid; 314: pw = &gw; 315: #endif TRUSTED 316: guest = 1; 317: goto anonymous; 318: } 319: #endif BPOP 320: if ((pw = getpwnam (username)) == NULL 321: || *pw -> pw_passwd == NULL 322: || strcmp (crypt (vec[1], pw -> pw_passwd), pw -> pw_passwd)) { 323: #ifdef TRUSTED 324: trusted (0, hostname, NULLCP, 0, pw ? pw -> pw_name : username, 325: pw && pw -> pw_uid == 0, "pop", "tcp", NULL); 326: #endif TRUSTED 327: return respond (NOTOK, "login incorrect"); 328: } 329: #else DPOP 330: #ifdef BPOP 331: if (isguest ()) { 332: #ifdef TRUSTED 333: static bboard gw; 334: 335: gw.bb_name = popbbuser; 336: pw = &gw; 337: #endif TRUSTED 338: guest = 1; 339: goto anonymous; 340: } 341: #endif BPOP 342: if (((pw = getbbnam (username)) == NULL 343: && (pw = getbbaka (username)) == NULL) 344: || *pw -> bb_passwd == NULL 345: || strcmp (crypt (vec[1], pw -> bb_passwd), pw -> bb_passwd)) { 346: #ifdef TRUSTED 347: trusted (0, hostname, NULLCP, 0, pw ? pw -> bb_name : username, 348: 0, "pop", "tcp", NULL); 349: #endif TRUSTED 350: return respond (NOTOK, "login incorrect"); 351: } 352: #endif DPOP 353: 354: #ifdef BPOP 355: anonymous: ; 356: #endif BPOP 357: #ifdef TRUSTED 358: if (trusted (1, hostname, NULLCP, 0, myhost, 359: #ifndef DPOP 360: pw -> pw_name, pw -> pw_uid == 0, 361: #else DPOP 362: pw -> bb_name, 0, 363: #endif DPOP 364: "pop", "tcp", NULL) 365: == 0) 366: return respond (NOTOK, "permission denied"); 367: #endif TRUSTED 368: return setup (pw, guest); 369: } 370: 371: /* */ 372: 373: #ifdef BPOP 374: static isguest () { 375: int i; 376: register char *cp; 377: char buffer[BUFSIZ]; 378: register FILE *fp; 379: 380: if (strcmp (username, popbbuser) || !guest_uid) 381: return FALSE; 382: if (popbblist == NULL || (fp = fopen (popbblist, "r")) == NULL) 383: return TRUE; 384: 385: i = FALSE; 386: if (hostname) 387: while (fgets (buffer, sizeof buffer, fp)) { 388: if (cp = index (buffer, '\n')) 389: *cp = NULL; 390: if (strcmp (buffer, hostname) == 0) { 391: i = TRUE; 392: break; 393: } 394: } 395: 396: (void) fclose (fp); 397: 398: return i; 399: } 400: #endif BPOP 401: 402: /* */ 403: 404: #ifdef RPOP 405: static int rpop (vec) 406: register char **vec; 407: { 408: #ifndef DPOP 409: register struct passwd *pw; 410: #else DPOP 411: register int hostok = 0; 412: register char *bp, 413: *cp; 414: char buffer[BUFSIZ]; 415: register struct bboard *pw; 416: #endif DPOP 417: 418: #ifndef DPOP 419: if (!rproto || (pw = getpwnam (username)) == NULL) { 420: #ifdef TRUSTED 421: trusted (0, hostname, vec[1], 0, username, 0, "rpop", "tcp", 422: NULL); 423: #endif TRUSTED 424: return respond (NOTOK, "login incorrect"); 425: } 426: if (chdir (pw -> pw_dir) == NOTOK && chdir ("/") == NOTOK) 427: return respond (NOTOK, "no remote directory"); 428: if (ruserok (hostname, pw -> pw_uid == 0, vec[1], username) == NOTOK) { 429: #ifdef TRUSTED 430: trusted (0, hostname, vec[1], 0, pw -> pw_name, 431: pw -> pw_uid == 0, "rpop", "tcp", NULL); 432: #endif TRUSTED 433: return respond (NOTOK, "permission denied"); 434: } 435: #else DPOP 436: if (!rproto 437: || ((pw = getbbnam (username)) == NULL 438: && (pw = getbbaka (username)) == NULL)) { 439: #ifdef TRUSTED 440: trusted (0, hostname, vec[1], 0, username, 0, "rpop", "tcp", 441: NULL); 442: #endif TRUSTED 443: return respond (NOTOK, "login incorrect"); 444: } 445: /* 446: * hacked by Dave Cohrs Tue Feb 4 14:12:15 CST 1986 447: * to allow the hostname to be a list: user@host1,user@host2 448: * NOTE: the separator must be a comma -- no spaces are allowed 449: */ 450: (void) sprintf (buffer, "%s@%s", vec[1], hostname); 451: for (bp = pw -> bb_addr; bp; bp = cp) { 452: if ((cp = index (bp, ','))) 453: *cp = NULL; 454: hostok = strcmp (bp, buffer) == 0; 455: if (cp) 456: *cp++ = ','; 457: if (hostok) 458: break; 459: } 460: if (!hostok) { 461: #ifdef TRUSTED 462: trusted (0, hostname, vec[1], 0, pw -> bb_name, 0, "rpop", 463: "tcp", NULL); 464: #endif TRUSTED 465: return respond (NOTOK, "permission denied"); 466: } 467: #endif DPOP 468: 469: #ifdef TRUSTED 470: if (trusted (1, hostname, vec[1], 0, username, 471: #ifndef DPOP 472: pw -> pw_uid == 0, 473: #else DPOP 474: 0, 475: #endif DPOP 476: "rpop", "tcp", NULL) 477: == 0) 478: return respond (NOTOK, "permission denied"); 479: #endif TRUSTED 480: return setup (pw, FALSE); 481: } 482: #endif RPOP 483: 484: /* */ 485: 486: static int setup (pw, guest) 487: #ifndef DPOP 488: register struct passwd *pw; 489: #else DPOP 490: register struct bboard *pw; 491: #endif DPOP 492: int guest; 493: { 494: #ifdef BPOP 495: if (guest) { 496: (void) setgid (guest_gid); 497: (void) initgroups (popbbuser, guest_gid); 498: (void) setuid (guest_uid); 499: } 500: else { 501: #endif BPOP 502: #ifndef DPOP 503: (void) setgid (pw -> pw_gid); 504: (void) initgroups (pw -> pw_name, pw -> pw_gid); 505: (void) setuid (pw -> pw_uid); 506: #else DPOP 507: (void) setgid (pop_gid); 508: (void) initgroups (POPUID, pop_gid); 509: (void) setuid (pop_uid); 510: #endif DPOP 511: #ifdef BPOP 512: } 513: #endif BPOP 514: 515: #ifndef DPOP 516: (void) sprintf (maildrop, "%s/%s", 517: mmdfldir && *mmdfldir ? mmdfldir : pw -> pw_dir, 518: mmdflfil && *mmdflfil ? mmdflfil : pw -> pw_name); 519: #else DPOP 520: (void) strcpy (maildrop, pw -> bb_file); 521: #endif DPOP 522: 523: if (setupaux (guest) == NOTOK) 524: return NOTOK; 525: 526: return respond (OK, 527: nmsgs ? "maildrop has %d message%s (%d octets)" : "maildrop empty", 528: nmsgs, nmsgs != 1 ? "s" : NULL, Msgs[0].m_size); 529: } 530: 531: /* */ 532: 533: static int setupaux (readonly) 534: int readonly; 535: { 536: register int i, 537: msgp; 538: struct stat st; 539: 540: #ifdef BPOP 541: xtnded = 0; 542: #endif BPOP 543: if ((dp = readonly ? fopen (maildrop, "r") : lkfopen (maildrop, "r")) 544: == NULL) 545: switch (errno) { 546: case ENOENT: 547: m_gMsgs (msgp = 0); 548: goto no_mail; 549: 550: default: 551: nmsgs = dmsgs = 0; 552: return respond (NOTOK, "unable to %s maildrop: \"%s\"", 553: readonly ? "read" : "lock", maildrop); 554: } 555: 556: if (fstat (fileno (dp), &st) != NOTOK) { 557: mode = (int) (st.st_mode & 0777), mtime = st.st_mtime; 558: msgp = read_map (maildrop, (long) st.st_size); 559: } 560: else { 561: mode = 0600, mtime = 0; 562: msgp = 0; 563: } 564: 565: if ((msgp = read_file (msgp ? Msgs[msgp].m_stop : 0L, msgp + 1)) < 1) 566: m_gMsgs (0); 567: 568: no_mail: ; 569: dmsgs = 0; 570: nmsgs = msgp; 571: 572: Msgs[0].m_flags = readonly ? MREAD : MNULL; 573: Msgs[0].m_size = 0; 574: for (i = 1; i <= nmsgs; i++) { 575: if (Msgs[i].m_size == 0) 576: Msgs[i].m_size = mbx_size (i); 577: Msgs[0].m_size += Msgs[i].m_size; 578: Msgs[i].m_flags = MNULL; 579: } 580: 581: return OK; 582: } 583: 584: /* */ 585: 586: static int read_map (file, pos) 587: char *file; 588: long pos; 589: { 590: register int i, 591: msgp; 592: register struct drop *pp, 593: *mp; 594: struct drop *rp; 595: 596: if (debug) 597: padvise (NULLCP, LOG_DEBUG, "read_map (%s, %ld)", file, pos); 598: 599: if ((i = map_read (file, pos, &rp, debug)) == 0) 600: return 0; 601: 602: m_gMsgs (i); 603: 604: msgp = 1; 605: for (pp = rp; i-- > 0; msgp++, pp++) { 606: mp = &Msgs[msgp].m_drop; 607: mp -> d_id = pp -> d_id; 608: mp -> d_size = pp -> d_size; 609: mp -> d_start = pp -> d_start; 610: mp -> d_stop = pp -> d_stop; 611: } 612: free ((char *) rp); 613: 614: return (msgp - 1); 615: } 616: 617: /* */ 618: 619: static int read_file (pos, msgp) 620: register long pos; 621: register int msgp; 622: { 623: register int i; 624: register struct drop *pp, 625: *mp; 626: struct drop *rp; 627: 628: if (debug) 629: padvise (NULLCP, LOG_DEBUG, "read_file (%ld, %d)", 630: pos, msgp); 631: 632: if ((i = mbx_read (dp, pos, &rp, debug)) <= 0) 633: return (msgp - 1); 634: 635: m_gMsgs ((msgp - 1) + i); 636: 637: for (pp = rp; i-- > 0; msgp++, pp++) { 638: mp = &Msgs[msgp].m_drop; 639: mp -> d_id = 0; 640: mp -> d_size = pp -> d_size; 641: mp -> d_start = pp -> d_start; 642: mp -> d_stop = pp -> d_stop; 643: } 644: free ((char *) rp); 645: 646: return (msgp - 1); 647: } 648: 649: /* */ 650: 651: static m_gMsgs (n) 652: int n; 653: { 654: if (debug) 655: padvise (NULLCP, LOG_DEBUG, "m_gMsgs (%d) 0x%x %d", 656: n, Msgs, nMsgs); 657: 658: if (Msgs == NULL) { 659: nMsgs = n + MAXFOLDER / 2; 660: Msgs = (struct Msg *) calloc ((unsigned) (nMsgs + 2), sizeof *Msgs); 661: if (Msgs == NULL) 662: padios (NULLCP, "unable to allocate Msgs structure"); 663: return; 664: } 665: 666: if (nMsgs >= n) 667: return; 668: 669: nMsgs = n + MAXFOLDER / 2; 670: Msgs = (struct Msg *) realloc ((char *) Msgs, 671: (unsigned) (nMsgs + 2) * sizeof *Msgs); 672: if (Msgs == NULL) 673: padios (NULLCP, "unable to reallocate Msgs structure"); 674: } 675: 676: /* */ 677: 678: static int mbx_size (m) 679: register int m; 680: { 681: register int i; 682: register long pos; 683: 684: (void) fseek (dp, Msgs[m].m_start, 0); 685: for (i = 0, pos = Msgs[m].m_stop - Msgs[m].m_start; pos > 0; i++, pos--) 686: if (fgetc (dp) == '\n') 687: i++; 688: 689: return i; 690: } 691: 692: /* */ 693: 694: /* ARGSUSED */ 695: 696: static int status (vec) 697: char **vec; 698: { 699: return respond (OK, "%d %d", nmsgs - dmsgs, Msgs[0].m_size); 700: } 701: 702: 703: static int list (vec) 704: register char **vec; 705: { 706: register int i; 707: 708: if (vec[1]) { 709: if ((i = atoi (vec[1])) <= 0 || i > nmsgs) 710: return respond (NOTOK, "no such message: \"%s\"", vec[1]); 711: if (Msgs[i].m_flags & MDELE) 712: return respond (NOTOK, "message %d is deleted", i); 713: 714: #ifndef BPOP 715: return respond (OK, "%d %d", i, Msgs[i].m_size); 716: #else BPOP 717: return respond (OK, xtnded ? "%d %d %d" : "%d %d", 718: i, Msgs[i].m_size, Msgs[i].m_id); 719: #endif BPOP 720: } 721: 722: (void) respond (OK, "%d message%s (%d octets)", 723: nmsgs - dmsgs, nmsgs - dmsgs != 1 ? "s" : NULL, 724: Msgs[0].m_size); 725: for (i = 1; i <= nmsgs; i++) 726: if (!(Msgs[i].m_flags & MDELE)) 727: #ifndef BPOP 728: multiline ("%d %d", i, Msgs[i].m_size); 729: #else BPOP 730: multiline (xtnded ? "%d %d %d" : "%d %d", 731: i, Msgs[i].m_size, Msgs[i].m_id); 732: #endif BPOP 733: multiend (); 734: 735: return OK; 736: } 737: 738: /* */ 739: 740: static int retrieve (vec) 741: register char **vec; 742: { 743: register int i; 744: register long pos; 745: register char *cp; 746: char buffer[BUFSIZ]; 747: 748: if ((i = atoi (vec[1])) <= 0 || i > nmsgs) 749: return respond (NOTOK, "no such message: \"%s\"", vec[1]); 750: if (Msgs[i].m_flags & MDELE) 751: return respond (NOTOK, "message %d is deleted", i); 752: 753: (void) respond (OK, "%d octets", Msgs[i].m_size); 754: 755: for ((void) fseek (dp, pos = Msgs[i].m_start, 0); 756: fgets (buffer, sizeof buffer, dp) != NULL && pos < Msgs[i].m_stop; 757: pos += (long) (cp - buffer + 1)) { 758: if (*(cp = buffer + strlen (buffer) - 1) == '\n') 759: *cp = NULL; 760: multiline ("%s", buffer); 761: } 762: multiend (); 763: 764: return OK; 765: } 766: 767: /* */ 768: 769: static int delete (vec) 770: register char **vec; 771: { 772: register int i; 773: 774: if (Msgs[0].m_flags & MREAD) 775: return respond (NOTOK, "maildrop is read-only"); 776: 777: if ((i = atoi (vec[1])) <= 0 || i > nmsgs) 778: return respond (NOTOK, "no such message: \"%s\"", vec[1]); 779: if (Msgs[i].m_flags & MDELE) 780: return respond (NOTOK, "message %d is deleted", i); 781: 782: Msgs[i].m_flags |= MDELE; 783: Msgs[0].m_size -= Msgs[i].m_size; 784: dmsgs++; 785: 786: return respond (OK, "message %d deleted (%d octets)", i, Msgs[i].m_size); 787: } 788: 789: 790: static int reset (vec) 791: char **vec; 792: { 793: register int i; 794: 795: for (i = 1; i <= nmsgs; i++) 796: if (Msgs[i].m_flags & MDELE) { 797: Msgs[i].m_flags &= ~MDELE; 798: Msgs[0].m_size += Msgs[i].m_size; 799: dmsgs--; 800: } 801: 802: return status (vec); 803: } 804: 805: /* */ 806: 807: static int top (vec) 808: register char **vec; 809: { 810: register int i, 811: j, 812: body, 813: lines; 814: register long pos; 815: register char *cp; 816: char buffer[BUFSIZ]; 817: 818: if ((i = atoi (vec[1])) <= 0 || i > nmsgs) 819: return respond (NOTOK, "no such message: \"%s\"", vec[1]); 820: if (Msgs[i].m_flags & MDELE) 821: return respond (NOTOK, "message %d is deleted", i); 822: if ((j = atoi (vec[2])) <= 0) 823: return respond (NOTOK, "bad number: \"%s\"", vec[2]); 824: 825: (void) respond (OK, vec[0]); 826: 827: body = lines = 0; 828: for ((void) fseek (dp, pos = Msgs[i].m_start, 0); 829: fgets (buffer, sizeof buffer, dp) != NULL && pos < Msgs[i].m_stop; 830: pos += (long) (cp - buffer + 1)) { 831: if (*(cp = buffer + strlen (buffer) - 1) == '\n') 832: *cp = NULL; 833: if (body) { 834: if (lines++ >= j) 835: break; 836: } 837: else 838: if (*buffer == NULL) 839: body++; 840: multiline ("%s", buffer); 841: } 842: multiend (); 843: 844: return OK; 845: } 846: 847: /* */ 848: 849: #ifdef BPOP 850: static int xtnd (vec) 851: register char **vec; 852: { 853: make_lower (vec[1], vec[1]); 854: 855: if (strcmp (vec[1], "bboards") == 0 || strcmp (vec[1], "archive") == 0) 856: return xtnd1 (vec); 857: if (strcmp (vec[1], "x-bboards") == 0) 858: return xtnd2 (vec); 859: 860: return respond (NOTOK, "unknown XTND command: \"%s\"", vec[1]); 861: } 862: 863: 864: static int xtnd1 (vec) 865: register char **vec; 866: { 867: register struct bboard *bb; 868: 869: if (vec[2]) { 870: make_lower (vec[2], vec[2]); 871: if ((bb = getbbaux (vec[2])) == NULL) 872: return respond (NOTOK, "unknown BBoard: \"%s\"", vec[2]); 873: 874: if (quitaux (NULLVP) == NOTOK) 875: return NOTOK; 876: (void) strcpy (maildrop, 877: strcmp (vec[1], "bboards") ? bb -> bb_archive : bb -> bb_file); 878: if (setupaux (TRUE) == NOTOK) 879: return NOTOK; 880: xtnded++; 881: (void) respond (OK, "%s", vec[1]); 882: multiline ("%s %d", bb -> bb_name, bb -> bb_maxima); 883: } 884: else { 885: if (strcmp (vec[1], "bboards")) 886: return respond (NOTOK, "too few arguments to XTND \"%s\"", vec[1]); 887: 888: (void) respond (OK, "%s", vec[1]); 889: for (bb = BBhead; bb; bb = bb -> bb_next) { 890: getbbmax (bb); 891: if (!(bb -> bb_flags & BB_INVIS)) 892: multiline ("%s %d", bb -> bb_name, bb -> bb_maxima); 893: } 894: while (bb = getbbaux (NULLCP)) 895: if (!(bb -> bb_flags & BB_INVIS)) 896: multiline ("%s %d", bb -> bb_name, bb -> bb_maxima); 897: } 898: multiend (); 899: 900: return OK; 901: } 902: 903: /* */ 904: 905: static int xtnd2 (vec) 906: register char **vec; 907: { 908: register char *cp, 909: **ap; 910: char buffer[BUFSIZ]; 911: register struct bboard *bb; 912: 913: if (vec[2] == NULL) 914: return respond (NOTOK, "too few arguments to XTND \"%s\"", vec[1]); 915: 916: make_lower (vec[2], vec[2]); 917: if ((bb = getbbaux (vec[2])) == NULL) 918: return respond (NOTOK, "unknown BBoard: \"%s\"", vec[2]); 919: 920: (void) respond (OK, "%s", vec[1]); 921: multiline ("%s", bb -> bb_name); 922: 923: cp = buffer; 924: for (ap = bb -> bb_aka; *ap; ap++) { 925: (void) sprintf (cp, cp != buffer ? " %s" : "%s", *ap); 926: cp += strlen (cp); 927: } 928: multiline ("%s", buffer); 929: 930: multiline ("%s", bb -> bb_file); 931: multiline ("%s", bb -> bb_archive); 932: multiline ("%s", bb -> bb_info); 933: multiline ("%s", bb -> bb_map); 934: multiline ("%s", bb -> bb_passwd); 935: 936: cp = buffer; 937: for (ap = bb -> bb_leader; *ap; ap++) { 938: (void) sprintf (cp, cp != buffer ? " %s" : "%s", *ap); 939: cp += strlen (cp); 940: } 941: multiline ("%s", buffer); 942: 943: multiline ("%s", bb -> bb_addr); 944: multiline ("%s", bb -> bb_request); 945: multiline ("%s", bb -> bb_relay); 946: 947: cp = buffer; 948: for (ap = bb -> bb_dist; *ap; ap++) { 949: (void) sprintf (cp, cp != buffer ? " %s" : "%s", *ap); 950: cp += strlen (cp); 951: } 952: multiline ("%s", buffer); 953: 954: getbbmax (bb); 955: multiline ("0%o %d", bb -> bb_flags, bb -> bb_maxima); 956: multiline ("%s", bb -> bb_date); 957: 958: multiend (); 959: 960: return OK; 961: } 962: 963: /* */ 964: 965: static struct bboard *getbbaux (s) 966: register char *s; 967: { 968: register struct bboard *bb; 969: struct stat st; 970: 971: if (BBhead == NULL) 972: if (setbbinfo (BBOARDS, BBDB, 1)) 973: BBtime = getbbtime (); 974: else 975: return NULL; 976: 977: if (s != NULLCP) 978: for (bb = BBhead; bb; bb = bb -> bb_next) 979: if (strcmp (bb -> bb_name, s) == 0) { 980: if (debug) 981: padvise (NULLCP, LOG_DEBUG, "getbbaux: \"%s\" from cache", 982: bb -> bb_name); 983: getbbmax (bb); 984: return bb; 985: } 986: 987: while (bb = getbbent ()) { 988: if ((bb = getbbcpy (bb)) == NULL) 989: return NULL; 990: 991: if (access (bb -> bb_file, 04) == NOTOK && errno == EACCES) 992: bb -> bb_flags |= BB_INVIS; 993: bb -> bb_mtime = stat (bb -> bb_info, &st) != NOTOK ? st.st_mtime : 0L; 994: 995: if (BBtail != NULL) 996: BBtail -> bb_next = bb; 997: if (BBhead == NULL) 998: BBhead = bb; 999: BBtail = bb; 1000: 1001: if (s == NULL || strcmp (bb -> bb_name, s) == 0) { 1002: if (s && debug) 1003: padvise (NULLCP, LOG_DEBUG, "getbbaux: \"%s\" from scratch", 1004: bb -> bb_name); 1005: return bb; 1006: } 1007: } 1008: 1009: return NULL; 1010: } 1011: 1012: /* */ 1013: 1014: static getbbmax (bb) 1015: register struct bboard *bb; 1016: { 1017: int i; 1018: register char *cp; 1019: char buffer[BUFSIZ]; 1020: struct stat st; 1021: register FILE * fp; 1022: 1023: if (debug) 1024: padvise (NULLCP, LOG_DEBUG, "getbbmax: \"%s\", 0%o, %d, %s", 1025: bb -> bb_name, bb -> bb_flags, bb -> bb_maxima, bb -> bb_date); 1026: 1027: if (!(bb -> bb_flags & BB_INVIS) 1028: && access (bb -> bb_file, 04) == NOTOK && errno == EACCES) 1029: bb -> bb_flags |= BB_INVIS; 1030: 1031: if (stat (bb -> bb_info, &st) == NOTOK 1032: || bb -> bb_mtime == st.st_mtime 1033: || (fp = fopen (bb -> bb_info, "r")) == NULL) 1034: return; 1035: bb -> bb_mtime = st.st_mtime; 1036: 1037: if (fgets (buffer, sizeof buffer, fp) && (i = atoi (buffer)) > 0) 1038: bb -> bb_maxima = i; 1039: if (!feof (fp) && fgets (buffer, sizeof buffer, fp)) { 1040: if (bb -> bb_date) 1041: free (bb -> bb_date); 1042: if (cp = index (buffer, '\n')) 1043: *cp = NULL; 1044: bb -> bb_date = getcpy (buffer); 1045: } 1046: 1047: (void) fclose (fp); 1048: 1049: if (debug) 1050: padvise (NULLCP, LOG_DEBUG, "updated: \"%s\", 0%o, %d, %s", 1051: bb -> bb_name, bb -> bb_flags, bb -> bb_maxima, bb -> bb_date); 1052: } 1053: #endif BPOP 1054: 1055: /* */ 1056: 1057: static int quit (vec) 1058: char **vec; 1059: { 1060: int d, 1061: n; 1062: 1063: d = dmsgs, n = nmsgs; 1064: 1065: if (quitaux (vec) == NOTOK) 1066: return NOTOK; 1067: 1068: #ifdef BPOP 1069: if (xtnded) 1070: return respond (OK, "%s signing off", server); 1071: #endif BPOP 1072: 1073: if (n == d) 1074: return respond (OK, "%s signing off (maildrop empty)", server); 1075: 1076: return respond (OK, 1077: n ? "%s signing off (%d message%s, %d octets left)" 1078: : "%s signing off (maildrop empty)", 1079: server, n - d, n - d != 1 ? "s" : NULL, Msgs[0].m_size); 1080: } 1081: 1082: 1083: static int quitaux (vec) 1084: char **vec; 1085: { 1086: int i; 1087: 1088: if (dp == NULL) 1089: return OK; 1090: 1091: i = quitfile (vec); 1092: 1093: nmsgs = dmsgs = 0; 1094: (void) lkfclose (dp, maildrop); 1095: dp = NULL; 1096: 1097: return i; 1098: } 1099: 1100: /* */ 1101: 1102: /* ARGSUSED */ 1103: 1104: static int quitfile (vec) 1105: char **vec; 1106: { 1107: register int i, 1108: md; 1109: char tmpfil[BUFSIZ], 1110: map1[BUFSIZ], 1111: map2[BUFSIZ]; 1112: struct stat st; 1113: 1114: if (dmsgs == 0 || (Msgs[0].m_flags & MREAD)) 1115: return OK; 1116: 1117: if (fstat (fileno (dp), &st) == NOTOK) 1118: return respond (NOTOK, "unable to stat file"); 1119: if (mtime != st.st_mtime) 1120: return respond (NOTOK, "new messages have arrived, no update"); 1121: mode = (int) (st.st_mode & 0777); 1122: 1123: if (nmsgs == dmsgs) { 1124: i = truncate (maildrop, 0); 1125: (void) unlink (map_name (maildrop));/* XXX */ 1126: if (i == NOTOK) 1127: return respond (NOTOK, "unable to zero %s", maildrop); 1128: return OK; 1129: } 1130: 1131: (void) strcpy (tmpfil, m_backup (maildrop)); 1132: if ((md = mbx_open (tmpfil, st.st_uid, st.st_gid, mode)) == NOTOK) 1133: return respond (NOTOK, "unable to create temporary file"); 1134: 1135: for (i = 1; i <= nmsgs; i++) 1136: if (!(Msgs[i].m_flags & MDELE) 1137: && mbx_write (tmpfil, md, dp, Msgs[i].m_id, Msgs[i].m_start, 1138: Msgs[i].m_stop, TRUE, debug) == NOTOK) { 1139: (void) mbx_close (tmpfil, md); 1140: (void) unlink (tmpfil); 1141: return respond (NOTOK, "error writing temporary file"); 1142: } 1143: (void) mbx_close (tmpfil, md); 1144: 1145: if ((i = rename (tmpfil, maildrop)) == OK) { 1146: (void) strcpy (map1, map_name (tmpfil)); 1147: (void) strcpy (map2, map_name (maildrop)); 1148: if (rename (map1, map2) == NOTOK) { 1149: (void) unlink (map1); 1150: (void) unlink (map2); 1151: } 1152: } 1153: 1154: if (i == NOTOK) 1155: return respond (NOTOK, "unable to rename maildrop"); 1156: 1157: return OK; 1158: } 1159: 1160: /* */ 1161: 1162: static struct vector *getvector (bp, vec) 1163: register char *bp, 1164: **vec; 1165: { 1166: register int i; 1167: register struct vector *v; 1168: 1169: for (i = 0; i < NVEC; i++) { 1170: while (isspace (*bp)) 1171: *bp++ = NULL; 1172: if (*bp == NULL) { 1173: vec[i] = NULL; 1174: break; 1175: } 1176: vec[i] = bp; 1177: while (!isspace (*bp)) 1178: bp++; 1179: } 1180: i--; 1181: vec[NVEC] = NULL; 1182: 1183: if (*bp != NULL) { 1184: (void) respond (NOTOK, "too many arguments"); 1185: return NULL; 1186: } 1187: if (*vec[0] == NULL) { 1188: (void) respond (NOTOK, "null command"); 1189: return NULL; 1190: } 1191: make_lower (vec[0], vec[0]); 1192: 1193: for (v = vectors; v -> v_cmd; v++) 1194: if (strcmp (v -> v_cmd, vec[0]) == 0 && v -> v_valid == mystate) { 1195: if (i < v -> v_min || v -> v_max < i) { 1196: (void) respond (NOTOK, "too %s arguments to \"%s\"", 1197: i < v -> v_min ? "few" : "many", vec[0]); 1198: return NULL; 1199: } 1200: else 1201: return v; 1202: } 1203: 1204: (void) respond (NOTOK, "unknown command: \"%s\"", vec[0]); 1205: return NULL; 1206: } 1207: 1208: /* */ 1209: 1210: /* VARARGS2 */ 1211: 1212: static int respond (code, fmt, a, b, c, d) 1213: char *fmt, 1214: *a, 1215: *b, 1216: *c, 1217: *d; 1218: int code; 1219: { 1220: register char *bp; 1221: char buffer[BUFSIZ]; 1222: 1223: bp = buffer; 1224: bp += strlen (sprintf (bp, "%s%s", code == OK ? "+OK" : "-ERR", 1225: fmt ? " " : NULL)); 1226: if (fmt) 1227: bp += strlen (sprintf (bp, fmt, a, b, c, d)); 1228: putline (buffer, output); 1229: 1230: return code; 1231: } 1232: 1233: 1234: /* VARARGS1 */ 1235: 1236: static multiline (fmt, a, b, c, d) 1237: char *fmt, 1238: *a, 1239: *b, 1240: *c, 1241: *d; 1242: { 1243: register char *cp; 1244: char buffer[BUFSIZ + TRMLEN]; 1245: 1246: (void) strcpy (buffer, TRM); 1247: cp = sprintf (buffer + TRMLEN, fmt, a, b, c, d); 1248: if (strncmp (cp, TRM, TRMLEN) == 0) 1249: cp = buffer; 1250: 1251: putline (cp, output); 1252: } 1253: 1254: 1255: static multiend () { 1256: putline (TRM, output); 1257: } 1258: 1259: /* */ 1260: 1261: static int getline (s, n, iop) 1262: register char *s; 1263: register int n; 1264: register FILE *iop; 1265: { 1266: register int c; 1267: register char *p; 1268: 1269: p = s; 1270: while (--n > 0 && (c = fgetc (iop)) != EOF) { 1271: while (c == IAC) { 1272: (void) fgetc (iop); 1273: c = fgetc (iop); 1274: } 1275: if ((*p++ = c) == '\n') 1276: break; 1277: } 1278: if (ferror (iop)) 1279: return NOTOK; 1280: if (c == EOF && p == s) 1281: return DONE; 1282: *p++ = NULL; 1283: if (debug) 1284: padvise (NULLCP, LOG_DEBUG, "<--- %s", s); 1285: 1286: return OK; 1287: } 1288: 1289: 1290: static putline (s, iop) 1291: register char *s; 1292: register FILE *iop; 1293: { 1294: (void) fprintf (iop, "%s\r\n", s); 1295: if (debug) 1296: padvise (NULLCP, LOG_DEBUG, "---> %s", s); 1297: 1298: (void) fflush (iop); 1299: } 1300: 1301: 1302: /* ARGSUSED */ 1303: 1304: static int pipeser (sig, code, sc) 1305: int sig; 1306: long code; 1307: struct sigcontext *sc; 1308: { 1309: padvise (NULLCP, LOG_WARNING, "lost connection"); 1310: 1311: _exit (NOTOK); 1312: }