|
|
1.1 root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.