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: }

Defined functions

delete defined in line 769; used 2 times
getbbaux defined in line 965; used 6 times
getbbmax defined in line 1014; used 3 times
getline defined in line 1261; used 1 times
getvector defined in line 1162; used 2 times
isguest defined in line 374; used 2 times
list defined in line 703; used 2 times
m_gMsgs defined in line 651; used 4 times
mbx_size defined in line 678; used 1 times
multiend defined in line 1255; used 5 times
multiline defined in line 1236; used 21 times
pass defined in line 296; used 2 times
pipeser defined in line 1304; used 2 times
pop defined in line 217; used 1 times
popassert defined in line 159; used 1 times
popinit defined in line 149; used 1 times
putline defined in line 1290; used 3 times
quit defined in line 1057; used 2 times
quitaux defined in line 1083; used 2 times
quitfile defined in line 1104; used 1 times
read_file defined in line 619; used 1 times
read_map defined in line 586; used 1 times
reset defined in line 790; used 2 times
respond defined in line 1212; used 55 times
retrieve defined in line 740; used 2 times
rpop defined in line 405; used 2 times
setup defined in line 486; used 2 times
setupaux defined in line 533; used 2 times
status defined in line 696; used 3 times
top defined in line 807; used 2 times
user defined in line 286; used 2 times
xtnd defined in line 850; used 2 times
xtnd1 defined in line 864; used 1 times
xtnd2 defined in line 905; used 1 times

Defined variables

BBhead defined in line 104; used 8 times
BBtail defined in line 105; used 5 times
BBtime defined in line 107; used 2 times
Msgs defined in line 127; used 56 times
dmsgs defined in line 130; used 11 times
guest_gid defined in line 102; used 4 times
guest_uid defined in line 101; used 5 times
hostname defined in line 88; used 13 times
maildrop defined in line 93; used 14 times
mode defined in line 94; used 4 times
mystate defined in line 32; used 6 times
nMsgs defined in line 126; used 6 times
nmsgs defined in line 129; used 19 times
pop_gid defined in line 84; used 3 times
pop_uid defined in line 83; used 2 times
rproto defined in line 87; used 3 times
server defined in line 89; used 8 times
username defined in line 91; used 15 times
vectors defined in line 52; used 1 times
xtnded defined in line 99; used 5 times

Defined struct's

Msg defined in line 113; used 6 times
vector defined in line 46; used 8 times

Defined enum's

state defined in line 30; used 4 times

Defined macros

FALSE defined in line 18; used 3 times
IAC defined in line 135; used 1 times
MDELE defined in line 122; used 9 times
MNULL defined in line 121; used 2 times
MREAD defined in line 123; used 3 times
NVEC defined in line 20; used 3 times
TRM defined in line 133; used 4 times
TRMLEN defined in line 134; used 3 times
TRUE defined in line 17; used 4 times
m_id defined in line 115; used 3 times
m_size defined in line 116; used 19 times
m_start defined in line 117; used 5 times
m_stop defined in line 118; used 5 times
Last modified: 1986-04-21
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4279
Valid CSS Valid XHTML 1.0 Strict