]> diplodocus.org Git - nmh/blob - docs/historical/mh-6.8.5/support/pop/popser.c
Fixed quoting of filename, expanded C-T parameter values, etc.,
[nmh] / docs / historical / mh-6.8.5 / support / pop / popser.c
1 /* popser.c - the POP service */
2 #ifndef lint
3 static char ident[]="@(#)$Id: popser.c,v 1.34 1995/12/07 18:54:35 jromine Exp $";
4 #endif
5
6 #include "../h/mh.h"
7 #include "../h/dropsbr.h"
8 #ifdef MPOP
9 #ifdef BPOP
10 #include "../h/formatsbr.h"
11 #include "../h/scansbr.h"
12 #endif
13 #endif /* MPOP */
14 #include "../zotnet/bboards.h"
15 #include <stdio.h>
16 #include "../zotnet/mts.h"
17 #include <ctype.h>
18 #include <errno.h>
19 #include <pwd.h>
20 #include <signal.h>
21 #include "syslog.h"
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #ifdef UNISTD
25 #include <unistd.h>
26 #endif
27 #ifdef KPOP
28 #include <krb.h>
29 #endif /* KPOP */
30 #ifdef SYS5
31 #include <fcntl.h>
32 #endif /* SYS5 */
33 #ifdef SHADOW
34 #include <shadow.h>
35 #endif /* SHADOW */
36
37
38 #define TRUE 1
39 #define FALSE 0
40
41 #define NVEC 5
42
43 #ifndef POPSERVICE
44 #define POPSERVICE "pop"
45 #endif
46
47 /* \f */
48
49 extern int errno;
50
51 extern int debug;
52 extern char myhost[];
53 extern char *myname;
54
55 #ifndef POP2
56 static enum state {
57 auth1, auth2, trans, update, halt, error
58 } mystate;
59 #else
60 static enum state {
61 auth1, auth2, trans, mbox, item, ack, update, halt, error
62 } mystate;
63 #endif
64
65
66 static int user (), pass ();
67 #ifdef BPOP
68 static isguest(), getbbmax();
69 #ifndef MPOP
70 static int xtnd1(), xtnd2();
71 #else
72 static int xtnd1(), xtnd2(), xtnd3 ();
73 #endif /* MPOP */
74 #endif /* BPOP */
75 #ifdef RPOP
76 static int rpop ();
77 #endif /* RPOP */
78 #ifdef APOP
79 static int apop ();
80 #endif
81 static int status (), list (), retrieve (), delete (), reset ();
82 static int top (), last ();
83 #ifdef BPOP
84 static int xtnd ();
85 #endif /* BPOP */
86 static int quit ();
87 #ifdef POP2
88 static int helo (), rdp2 (), acks (), ack2 (), fold (), nack ();
89 #endif /* POP2 */
90
91 static struct vector {
92 char *v_cmd;
93 int v_min, v_max;
94 int (*v_vec) ();
95 enum state v_valid;
96 enum state v_win, v_lose;
97 } vectors[] = {
98 "user", 1, 1, user, auth1, auth2, auth1,
99 "pass", 1, 1, pass, auth2, trans, auth1,
100 #ifdef RPOP
101 "rpop", 1, 1, rpop, auth2, trans, auth1,
102 #endif /* RPOP */
103 #ifdef APOP
104 "apop", 2, 2, apop, auth1, trans, auth1,
105 #endif
106 "quit", 0, 0, NULL, auth1, halt, halt,
107 "quit", 0, 0, NULL, auth2, halt, halt,
108
109 "stat", 0, 0, status, trans, trans, trans,
110 "list", 0, 1, list, trans, trans, trans,
111 "retr", 1, 1, retrieve, trans, trans, trans,
112 "dele", 1, 1, delete, trans, trans, trans,
113 "noop", 0, 0, NULL, trans, trans, trans,
114 "rset", 0, 0, reset, trans, trans, trans,
115
116 "top", 2, 2, top, trans, trans, trans,
117 "last", 0, 0, last, trans, trans, trans,
118 #ifdef BPOP
119 #ifndef MPOP
120 "xtnd", 1, 2, xtnd, trans, trans, trans,
121 #else
122 "xtnd", 1, 3, xtnd, trans, trans, trans,
123 #endif /* MPOP */
124 #endif /* BPOP */
125 "quit", 0, 0, quit, trans, halt, halt,
126
127 #ifdef POP2
128 "helo", 2, 2, helo, auth1, mbox, auth1,
129
130 "fold", 1, 1, fold, mbox, mbox, mbox,
131 "quit", 0, 0, quit, mbox, halt, halt,
132 "read", 0, 1, rdp2, mbox, item, error,
133
134 "fold", 1, 1, fold, item, mbox, mbox,
135 "read", 0, 1, rdp2, item, item, error,
136 "quit", 0, 0, quit, item, halt, halt,
137 "retr", 0, 0, retrieve, item, ack, error,
138
139 "acks", 0, 0, ack2, ack, item, error,
140 "ackd", 0, 0, ack2, ack, item, error,
141 "nack", 0, 0, rdp2, ack, item, error,
142 "quit", 0, 0, NULL, ack, halt, halt,
143
144 #endif /* POP2 */
145 NULL
146 };
147
148 static struct vector *getvector ();
149
150 /* \f */
151
152 #ifdef POP2
153 static int pop2 = NOTOK; /* current pop2 msg, or NOTOK if pop3 */
154 #endif /* POP2 */
155 #ifdef DPOP
156 static int pop_uid;
157 static int pop_gid;
158 #endif /* DPOP */
159
160 static int rproto;
161 static char *hostname;
162 static char server[BUFSIZ];
163 static char timestamp[BUFSIZ];
164
165 static char username[BUFSIZ];
166
167 static char maildrop[BUFSIZ];
168 static int mode;
169 static time_t mtime;
170 static FILE *dp;
171
172 static long lastseen;
173 static int rmsgs;
174
175 #ifdef BPOP
176 static int xtnded;
177
178 static int guest_uid;
179 static int guest_gid;
180
181 static struct bboard *BBhead = NULL;
182 static struct bboard *BBtail = NULL;
183
184 static long BBtime = 0L;
185
186 static struct bboard *getbbaux ();
187 #endif /* BPOP */
188
189
190 struct Msg { /* Msgs[0] contains info for entire maildrop */
191 struct drop m_drop;
192 #define m_id m_drop.d_id
193 #define m_size m_drop.d_size
194 #define m_last m_drop.d_start /* Msgs[i = 0] */
195 #define m_start m_drop.d_start /* Msgs[i > 0] */
196 #define m_stop m_drop.d_stop
197
198 unsigned m_flags;
199 #define MNULL 0x00
200 #define MDELE 0x01
201 #define MREAD 0x02
202 };
203
204 static int nMsgs = 0;
205 static struct Msg *Msgs = NULL;
206
207 static int nmsgs;
208 static int dmsgs;
209 #ifdef MPOP
210 #ifdef BPOP
211 static int _sc_width = 0;
212 static char *nfs = NULL;
213 #endif
214 #endif /* MPOP */
215
216
217 #define TRM "."
218 #define TRMLEN (sizeof TRM - 1)
219 #define IAC 255
220
221 static TYPESIG pipeser ();
222
223 FILE *input;
224 FILE *output;
225
226 #ifndef __STDC__
227 #ifdef SYS5
228 struct passwd *getpwnam();
229 #endif
230 #endif
231
232 void padvise (), padios ();
233 char *crypt ();
234
235 #ifdef POPUUMBOX
236 #define MBX_READ pmbx_read
237 static int pmbx_read ();
238 static char *p_copy(), *p_copyin(), *p_nextword();
239 static p_cmatch(), p_isdate(), p_ishead(), p_parse(), any();
240 #else
241 #define MBX_READ mbx_read
242 #endif
243 extern int mbx_read ();
244
245 static int setup(), setupaux(), read_map(), read_file(), pmbx_size();
246 static int quitaux(), quitfile(), respond(), getline();
247 static m_gMsgs(), multiline(), multiend(), putline();
248 /* \f */
249
250 popinit () {
251 #ifdef BPOP
252 padvise (NULLCP, LOG_INFO, "initialize list of BBoards");
253
254 BBhead = BBtail = NULL;
255 while (getbbaux (NULLCP))
256 continue;
257 #endif /* BPOP */
258 }
259
260 popassert () {
261 #ifdef BPOP
262 register char **p;
263 register struct bboard *bb,
264 *bp;
265
266 if (BBtime == getbbtime ())
267 return;
268
269 padvise (NULLCP, LOG_INFO, "list of BBoards has changed");
270
271 for (bb = BBhead; bb; bb = bp) {
272 bp = bb -> bb_next;
273
274 if (bb -> bb_name)
275 free (bb -> bb_name);
276 if (bb -> bb_file)
277 free (bb -> bb_file);
278 if (bb -> bb_archive)
279 free (bb -> bb_archive);
280 if (bb -> bb_info)
281 free (bb -> bb_info);
282 if (bb -> bb_map)
283 free (bb -> bb_map);
284 if (bb -> bb_passwd)
285 free (bb -> bb_passwd);
286 if (bb -> bb_date)
287 free (bb -> bb_date);
288 if (bb -> bb_addr)
289 free (bb -> bb_addr);
290 if (bb -> bb_request)
291 free (bb -> bb_request);
292 if (bb -> bb_relay)
293 free (bb -> bb_relay);
294
295 for (p = bb -> bb_aka; *p; p++)
296 free (*p);
297 free ((char *) bb -> bb_aka);
298
299 for (p = bb -> bb_leader; *p; p++)
300 free (*p);
301 free ((char *) bb -> bb_leader);
302
303 for (p = bb -> bb_dist; *p; p++)
304 free (*p);
305 free ((char *) bb -> bb_dist);
306
307 free ((char *) bb);
308 }
309
310 BBhead = BBtail = NULL;
311 while (getbbaux (NULLCP))
312 continue;
313 #endif /* BPOP */
314 }
315
316 /* \f */
317
318 #ifdef KPOP
319 static char *kusername;
320
321 kpop (in, out, principal, rhost, auth)
322 int in,
323 out;
324 char *principal, *rhost;
325 int auth;
326 #else /* KPOP */
327 pop (in, out, priv, rhost)
328 int in,
329 out,
330 priv;
331 char *rhost;
332 #endif /* KPOP */
333 {
334 char buffer[BUFSIZ],
335 *vec[NVEC + 1];
336 #if defined (DPOP) || defined (BPOP)
337 register struct passwd *pw;
338 #endif /* defined (DPOP) || defined (BPOP) */
339 register struct vector *v;
340
341 m_foil (NULLCP);
342 mts_init (myname);
343
344 hostname = rhost;
345 #ifdef KPOP
346 rproto = 1;
347 (void) sprintf (server, "%s KPOP server", myhost);
348 #else
349 rproto = priv;
350 (void) sprintf (server, "%s server", priv ? "RPOP" : "POP");
351 #endif /* KPOP */
352
353 if ((input = fdopen (in, "r")) == NULL
354 || (output = fdopen (out, "w")) == NULL) {/* you lose big */
355 (void) respond (NOTOK, "%s loses on initialization", server);
356 return;
357 }
358 (void) signal (SIGPIPE, pipeser);
359 #ifdef KPOP
360 if (principal == NULLCP) {
361 char buf[512];
362 strcpy(buf, "Authentication failed: ");
363 strcat(buf, krb_err_txt[auth]);
364 (void) respond (NOTOK, buf);
365 return;
366 }
367 kusername = principal;
368 #endif /* KPOP */
369
370 #ifdef DPOP
371 if ((pw = getpwnam (POPUID)) == NULL || !setpwinfo (pw, POPDB, 1)) {
372 (void) respond (NOTOK, "%s loses on DB initialization -- %s",
373 server, pw ? getbberr () : "POP user-id unknown");
374 return;
375 }
376 pop_uid = pw -> pw_uid;
377 pop_gid = pw -> pw_gid;
378 #endif /* DPOP */
379 #ifdef BPOP
380 if ((pw = getpwnam (popbbuser)) && pw -> pw_uid) {
381 guest_uid = pw -> pw_uid;
382 guest_gid = pw -> pw_gid;
383 }
384 else
385 guest_uid = guest_gid = 0;
386 #endif /* BPOP */
387
388 {
389 long clock;
390
391 (void) time (&clock);
392 (void) sprintf (timestamp, "<%d.%ld@%s>", getpid (), clock, myhost);
393 }
394 (void) respond (OK, "%s ready %s", server, timestamp);
395
396 for (mystate = auth1; mystate != halt && mystate != error;)
397 switch (getline (buffer, sizeof buffer, input)) {
398 case OK:
399 if ((v = getvector (buffer, vec)) == NULL)
400 continue;
401 mystate = (v -> v_vec ? (v -> v_vec) (vec)
402 : respond (OK, NULLCP)) == OK
403 ? v -> v_win
404 : v -> v_lose;
405 break;
406
407 case NOTOK:
408 case DONE:
409 mystate = error;
410 (void) respond (NOTOK, "%s signing off", server);
411 break;
412 }
413 }
414
415 /* \f */
416 #ifdef POP2
417 static int helo (vec) /* sort of "user" and "pass" */
418 register char **vec;
419 {
420 pop2 = 0; /* now we're talkin' pop2! */
421 make_lower (username, vec[1]); /* helo user pass */
422 return pass (++vec); /* user pass */
423 }
424 #endif
425
426 static int user (vec)
427 register char **vec;
428 {
429 make_lower (username, vec[1]);
430 #ifdef KPOP
431 if (!strcmp(username, kusername))
432 return respond (OK, "Kerberos authentication succeeded. Send username as password (%s)", username);
433 else {
434 respond (NOTOK, "Wrong username supplied (%s vs. %s)",
435 kusername, username);
436 return (NOTOK);
437 }
438 #else
439 return respond (OK, "password required for %s", username);
440 #endif
441 }
442
443 /* \f */
444
445 static int pass (vec)
446 register char **vec;
447 {
448 int guest = 0;
449 #ifndef DPOP
450 register struct passwd *pw;
451 #ifdef SHADOW
452 register struct spwd *shpw;
453 #endif /* SHADOW */
454 #else /* DPOP */
455 register struct bboard *pw;
456 #endif /* DPOP */
457
458 #ifdef KPOP
459 #ifndef DPOP
460 if ((pw = getpwnam (username)) != NULL)
461 return setup(pw, FALSE);
462 else
463 return respond (NOTOK, "no local password entry");
464 #else
465 {
466 static struct bboard entry;
467 static char entry_file[BUFSIZ] = "/usr/spool/pop";
468
469 pw = &entry;
470 pw->bb_name = username;
471 strcat(entry_file, username);
472 pw->bb_file = entry_file;
473 return setup(pw, FALSE);
474 }
475 #endif
476 #else /* KPOP */
477
478 #ifndef DPOP
479 #ifdef BPOP
480 if (isguest ()) {
481 #ifdef TRUSTED
482 static passwd gw;
483
484 gw.pw_name = popbbuser;
485 gw.pw_uid = guest_uid;
486 pw = &gw;
487 #endif /* TRUSTED */
488 guest = 1;
489 goto anonymous;
490 }
491 #endif /* BPOP */
492 if ((pw = getpwnam (username)) == NULL
493 #ifndef SHADOW
494 || *pw -> pw_passwd == NULL
495 || strcmp (crypt (vec[1], pw -> pw_passwd), pw -> pw_passwd)) {
496 #else /* SHADOW */
497 || (shpw = getspnam (username)) == NULL
498 || *shpw -> sp_pwdp == NULL
499 || strcmp (crypt (vec[1], shpw -> sp_pwdp), shpw -> sp_pwdp)) {
500 #endif /* SHADOW */
501 #ifdef TRUSTED
502 trusted (0, hostname, NULLCP, 0, pw ? pw -> pw_name : username,
503 pw && pw -> pw_uid == 0, POPSERVICE, "tcp", NULL);
504 #endif /* TRUSTED */
505 return respond (NOTOK, "login incorrect");
506 }
507 #else /* DPOP */
508 #ifdef BPOP
509 if (isguest ()) {
510 static struct bboard gw;
511
512 gw.bb_name = popbbuser;
513 pw = &gw;
514 guest = 1;
515 goto anonymous;
516 }
517 #endif /* BPOP */
518 if (((pw = getbbnam (username)) == NULL
519 && (pw = getbbaka (username)) == NULL)
520 || *pw -> bb_passwd == NULL
521 || strcmp (crypt (vec[1], pw -> bb_passwd), pw -> bb_passwd)) {
522 #ifdef TRUSTED
523 trusted (0, hostname, NULLCP, 0, pw ? pw -> bb_name : username,
524 0, POPSERVICE, "tcp", NULL);
525 #endif /* TRUSTED */
526 return respond (NOTOK, "login incorrect");
527 }
528 #endif /* DPOP */
529
530 #ifdef BPOP
531 anonymous: ;
532 #endif /* BPOP */
533 #ifdef TRUSTED
534 if (trusted (1, hostname, NULLCP, 0, myhost,
535 #ifndef DPOP
536 pw -> pw_name, pw -> pw_uid == 0,
537 #else /* DPOP */
538 pw -> bb_name, 0,
539 #endif /* DPOP */
540 POPSERVICE, "tcp", NULL)
541 == 0)
542 return respond (NOTOK, "permission denied");
543 #endif /* TRUSTED */
544 return setup (pw, guest);
545 #endif /* KPOP */
546 }
547
548 /* \f */
549
550 #ifdef BPOP
551 static isguest () {
552 int i;
553 register char *cp;
554 char buffer[BUFSIZ];
555 register FILE *fp;
556
557 if (strcmp (username, popbbuser) || !guest_uid)
558 return FALSE;
559 if (popbblist == NULL || (fp = fopen (popbblist, "r")) == NULL)
560 return TRUE;
561
562 i = FALSE;
563 if (hostname)
564 while (fgets (buffer, sizeof buffer, fp)) {
565 if (cp = index (buffer, '\n'))
566 *cp = NULL;
567 if (strcmp (buffer, hostname) == 0) {
568 i = TRUE;
569 break;
570 }
571 }
572
573 (void) fclose (fp);
574
575 return i;
576 }
577 #endif /* BPOP */
578
579 /* \f */
580
581 #ifdef RPOP
582 static int rpop (vec)
583 register char **vec;
584 {
585 #ifndef DPOP
586 register struct passwd *pw;
587 #else /* DPOP */
588 register int hostok = 0;
589 register char *bp,
590 *cp;
591 char buffer[BUFSIZ];
592 register struct bboard *pw;
593 #endif /* DPOP */
594
595 #ifndef DPOP
596 if (!rproto || (pw = getpwnam (username)) == NULL) {
597 #ifdef TRUSTED
598 trusted (0, hostname, vec[1], 0, username, 0, "rpop", "tcp",
599 NULL);
600 #endif /* TRUSTED */
601 return respond (NOTOK, "login incorrect");
602 }
603 if (chdir (pw -> pw_dir) == NOTOK && chdir ("/") == NOTOK)
604 return respond (NOTOK, "no remote directory");
605 if (ruserok (hostname, pw -> pw_uid == 0, vec[1], username) == NOTOK) {
606 #ifdef TRUSTED
607 trusted (0, hostname, vec[1], 0, pw -> pw_name,
608 pw -> pw_uid == 0, "rpop", "tcp", NULL);
609 #endif /* TRUSTED */
610 return respond (NOTOK, "permission denied");
611 }
612 #else /* DPOP */
613 if (!rproto
614 || ((pw = getbbnam (username)) == NULL
615 && (pw = getbbaka (username)) == NULL)) {
616 #ifdef TRUSTED
617 trusted (0, hostname, vec[1], 0, username, 0, "rpop", "tcp",
618 NULL);
619 #endif /* TRUSTED */
620 return respond (NOTOK, "login incorrect");
621 }
622 /*
623 * hacked by Dave Cohrs Tue Feb 4 14:12:15 CST 1986
624 * to allow the hostname to be a list: user@host1,user@host2
625 * NOTE: the separator must be a comma -- no spaces are allowed
626 */
627 (void) sprintf (buffer, "%s@%s", vec[1], hostname);
628 for (bp = pw -> bb_addr; bp; bp = cp) {
629 if ((cp = index (bp, ',')))
630 *cp = 0;
631 hostok = uleq (bp, buffer);
632 if (cp)
633 *cp++ = ',';
634 if (hostok)
635 break;
636 }
637 if (!hostok) {
638 #ifdef TRUSTED
639 trusted (0, hostname, vec[1], 0, pw -> bb_name, 0, "rpop",
640 "tcp", NULL);
641 #endif /* TRUSTED */
642 return respond (NOTOK, "permission denied");
643 }
644 #endif /* DPOP */
645
646 #ifdef TRUSTED
647 if (trusted (1, hostname, vec[1], 0, username,
648 #ifndef DPOP
649 pw -> pw_uid == 0,
650 #else /* DPOP */
651 0,
652 #endif /* DPOP */
653 "rpop", "tcp", NULL)
654 == 0)
655 return respond (NOTOK, "permission denied");
656 #endif /* TRUSTED */
657 return setup (pw, FALSE);
658 }
659 #endif /* RPOP */
660
661 /* \f */
662
663 #ifdef APOP
664 #include "popauth.h"
665 #include "../../uip/md5.c"
666 #include <ndbm.h>
667 #include <sys/file.h>
668 #ifdef SYS5
669 #include <fcntl.h>
670 #endif
671
672
673 static int apop (vec)
674 register char **vec;
675 {
676 register char *cp;
677 char buffer[BUFSIZ];
678 register unsigned char *dp;
679 unsigned char *ep,
680 digest[16];
681 #ifndef DPOP
682 register struct passwd *pw;
683 #else
684 register struct bboard *pw;
685 #endif
686 struct stat st;
687 datum key,
688 value;
689 DBM *db;
690 MD5_CTX mdContext;
691 struct authinfo auth;
692
693 (void) strcpy (username, vec[1]);
694
695 #ifndef DPOP
696 if ((pw = getpwnam (username)) == NULL
697 || *pw -> pw_passwd == NULL) {
698 return respond (NOTOK, "user invalid");
699 }
700 #else
701 if (((pw = getbbnam (username)) == NULL
702 && (pw = getbbaka (username)) == NULL)
703 || *pw -> bb_passwd == NULL) {
704 return respond (NOTOK, "subscriber invalid");
705 }
706 #endif
707
708 if ((db = dbm_open (APOP, O_RDONLY, 0)) == NULL)
709 return respond (NOTOK, "POP authorization DB not available (%d)",
710 errno);
711 if (fstat (dbm_pagfno (db), &st) != NOTOK
712 && (st.st_mode & 0777) != 0600) {
713 dbm_close (db);
714 return respond (NOTOK, "POP authorization DB has wrong mode (0%o)",
715 st.st_mode & 0777);
716 }
717 if (flock (dbm_pagfno (db), LOCK_SH) == NOTOK) {
718 dbm_close (db);
719 return respond (NOTOK, "unable to lock POP authorization DB (%d)",
720 errno);
721 }
722 key.dsize = strlen (key.dptr = vec[1]) + 1;
723 value = dbm_fetch (db, key);
724 if (value.dptr == NULL) {
725 dbm_close (db);
726 return respond (NOTOK, "not authorized");
727 }
728 bcopy (value.dptr, (char *) &auth, sizeof auth);
729 (void) sprintf (cp = buffer, "%s%*.*s", timestamp, auth.auth_secretlen,
730 auth.auth_secretlen, auth.auth_secret);
731
732 dbm_close (db);
733
734 MD5Init (&mdContext);
735 MD5Update (&mdContext, (unsigned char *) buffer,
736 (unsigned int) (strlen (timestamp) + auth.auth_secretlen));
737 MD5Final (digest, &mdContext);
738
739 cp = buffer;
740 for (ep = (dp = digest) + sizeof digest / sizeof digest[0];
741 dp < ep;
742 cp += 2)
743 (void) sprintf (cp, "%02x", *dp++ & 0xff);
744 *cp = NULL;
745
746 if (strcmp (vec[2], buffer))
747 return respond (NOTOK, "authentication failure");
748
749 return setup (pw, 0);
750 }
751 #endif
752
753 /* \f */
754
755 static int setup (pw, guest)
756 #ifndef DPOP
757 register struct passwd *pw;
758 #else /* DPOP */
759 register struct bboard *pw;
760 #endif /* DPOP */
761 int guest;
762 {
763 #ifdef BPOP
764 if (guest) {
765 (void) setgid (guest_gid);
766 #ifndef SYS5
767 (void) initgroups (popbbuser, guest_gid);
768 #endif /* SYS5 */
769 (void) setuid (guest_uid);
770 }
771 else {
772 #endif /* BPOP */
773 #ifndef DPOP
774 (void) setgid (pw -> pw_gid);
775 #ifndef SYS5
776 (void) initgroups (pw -> pw_name, pw -> pw_gid);
777 #endif /* SYS5 */
778 (void) setuid (pw -> pw_uid);
779 #else /* DPOP */
780 (void) setgid (pop_gid);
781 #ifndef SYS5
782 (void) initgroups (POPUID, pop_gid);
783 #endif /* SYS5 */
784 (void) setuid (pop_uid);
785 #endif /* DPOP */
786 #ifdef BPOP
787 }
788 #endif /* BPOP */
789
790 #ifndef DPOP
791 (void) sprintf (maildrop, "%s/%s",
792 mmdfldir && *mmdfldir ? mmdfldir : pw -> pw_dir,
793 mmdflfil && *mmdflfil ? mmdflfil : pw -> pw_name);
794 #else /* DPOP */
795 (void) strcpy (maildrop, pw -> bb_file);
796 #endif /* DPOP */
797
798 if (setupaux (guest) == NOTOK)
799 return NOTOK;
800
801 #ifdef POP2
802 if (pop2 != NOTOK) { /* in response to pop2 "helo" */
803 pop2 = nmsgs > 0 ? 1 : 0;
804 return respond ('#', "%d message%s (%d octets)",
805 nmsgs, nmsgs != 1 ? "s" : "", Msgs[0].m_size);
806 }
807 else
808 #endif /* POP2 */
809 return respond (OK,
810 nmsgs ? "maildrop has %d message%s (%d octets)" : "maildrop empty",
811 nmsgs, nmsgs != 1 ? "s" : "", Msgs[0].m_size);
812 }
813
814 /* \f */
815
816 static int setupaux (readonly)
817 int readonly;
818 {
819 register int i,
820 msgp;
821 struct stat st;
822
823 #ifdef BPOP
824 xtnded = 0;
825 #endif /* BPOP */
826 if ((dp = readonly ? fopen (maildrop, "r") : lkfopen (maildrop, "r"))
827 == NULL)
828 switch (errno) {
829 case ENOENT:
830 m_gMsgs (msgp = 0);
831 goto no_mail;
832
833 default:
834 nmsgs = dmsgs = 0;
835 return respond (NOTOK, "unable to %s maildrop: \"%s\"",
836 readonly ? "read" : "lock", maildrop);
837 }
838
839 if (fstat (fileno (dp), &st) != NOTOK) {
840 mode = (int) (st.st_mode & 0777), mtime = st.st_mtime;
841 msgp = read_map (maildrop, (long) st.st_size);
842 }
843 else {
844 mode = 0600, mtime = 0;
845 msgp = 0;
846 }
847
848 if ((msgp = read_file (msgp ? Msgs[msgp].m_stop : 0L, msgp + 1)) < 1)
849 m_gMsgs (0);
850
851 no_mail: ;
852 lastseen = Msgs[0].m_last;
853 if(debug)padvise(NULLCP,LOG_DEBUG,"XXX: lastseen=%d",lastseen);
854 dmsgs = rmsgs = 0;
855 nmsgs = msgp;
856
857 Msgs[0].m_flags = readonly ? MREAD : MNULL;
858 Msgs[0].m_size = 0;
859 for (i = 1; i <= nmsgs; i++) {
860 if (Msgs[i].m_size == 0)
861 Msgs[i].m_size = pmbx_size (i);
862 Msgs[0].m_size += Msgs[i].m_size;
863 Msgs[i].m_flags = MNULL;
864 }
865
866 return OK;
867 }
868
869 /* \f */
870
871 static int read_map (file, pos)
872 char *file;
873 long pos;
874 {
875 register int i,
876 msgp;
877 register struct drop *pp,
878 *mp;
879 struct drop *rp;
880
881 if (debug)
882 padvise (NULLCP, LOG_DEBUG, "read_map (%s, %ld)", file, pos);
883
884 if ((i = map_read (file, pos, &rp, debug)) == 0)
885 return 0;
886
887 m_gMsgs (i);
888
889 Msgs[0].m_last = rp -> d_start;
890
891 msgp = 1;
892 for (pp = rp + 1; i-- > 0; msgp++, pp++) {
893 mp = &Msgs[msgp].m_drop;
894 mp -> d_id = pp -> d_id;
895 mp -> d_size = pp -> d_size;
896 mp -> d_start = pp -> d_start;
897 mp -> d_stop = pp -> d_stop;
898 }
899 free ((char *) rp);
900
901 if (Msgs[0].m_last > msgp) {
902 if (debug)
903 padvise (NULLCP, LOG_DEBUG, "lastseen adjusted from %d to %d",
904 Msgs[0].m_last, msgp);
905 Msgs[0].m_last = msgp;
906 }
907
908 return (msgp - 1);
909 }
910
911 /* \f */
912
913 static int read_file (pos, msgp)
914 register long pos;
915 register int msgp;
916 {
917 register int i;
918 register struct drop *pp,
919 *mp;
920 struct drop *rp;
921
922 if (debug)
923 padvise (NULLCP, LOG_DEBUG, "read_file (%ld, %d)",
924 pos, msgp);
925
926 if ((i = MBX_READ (dp, pos, &rp, debug)) <= 0)
927 return (msgp - 1);
928
929 m_gMsgs ((msgp - 1) + i);
930
931 for (pp = rp; i-- > 0; msgp++, pp++) {
932 mp = &Msgs[msgp].m_drop;
933 mp -> d_id = 0;
934 mp -> d_size = pp -> d_size;
935 mp -> d_start = pp -> d_start;
936 mp -> d_stop = pp -> d_stop;
937 }
938 free ((char *) rp);
939
940 return (msgp - 1);
941 }
942
943 /* \f */
944
945 static m_gMsgs (n)
946 int n;
947 {
948 if (debug)
949 padvise (NULLCP, LOG_DEBUG, "m_gMsgs (%d) 0x%x %d",
950 n, Msgs, nMsgs);
951
952 if (Msgs == NULL) {
953 nMsgs = n + MAXFOLDER / 2;
954 Msgs = (struct Msg *) calloc ((unsigned) (nMsgs + 2), sizeof *Msgs);
955 if (Msgs == NULL)
956 padios (NULLCP, "unable to allocate Msgs structure");
957 return;
958 }
959
960 if (nMsgs >= n)
961 return;
962
963 nMsgs = n + MAXFOLDER / 2;
964 Msgs = (struct Msg *) realloc ((char *) Msgs,
965 (unsigned) (nMsgs + 2) * sizeof *Msgs);
966 if (Msgs == NULL)
967 padios (NULLCP, "unable to reallocate Msgs structure");
968 }
969
970 /* \f */
971
972 static int pmbx_size (m)
973 register int m;
974 {
975 register int i;
976 register long pos;
977
978 (void) fseek (dp, Msgs[m].m_start, 0);
979 for (i = 0, pos = Msgs[m].m_stop - Msgs[m].m_start; pos > 0; i++, pos--)
980 if (fgetc (dp) == '\n')
981 i++;
982
983 return i;
984 }
985
986 /* \f */
987
988 /* ARGSUSED */
989
990 static int status (vec)
991 char **vec;
992 {
993 return respond (OK, "%d %d", nmsgs - dmsgs, Msgs[0].m_size);
994 }
995
996
997 #ifdef POP2
998 static int rdp2 (vec) /* always returns OK */
999 char **vec;
1000 {
1001 if (vec[1]) {
1002 if ((pop2 = atoi (vec[1])) <= 0)
1003 pop2 = 0;
1004 }
1005 else if (pop2 == 0)
1006 return NOTOK; /* close 'em down */
1007
1008 if (pop2 <= 0 || pop2 > nmsgs) {
1009 pop2 = 0;
1010 return respond ('=', "0 no message");
1011 }
1012 if (Msgs[pop2].m_flags & MDELE) {
1013 pop2 = 0;
1014 return respond ('=', "0 message %d is deleted", pop2);
1015 }
1016
1017 return respond ('=', "%d (message %d)", Msgs[pop2].m_size, pop2);
1018 }
1019
1020 static int ack2 (vec)
1021 char **vec;
1022 {
1023 if (strcmp (vec[0], "ackd") == 0) {
1024 Msgs[pop2].m_flags |= MDELE; /* ignored later if MREAD */
1025 Msgs[0].m_size -= Msgs[pop2].m_size;
1026 dmsgs++;
1027 }
1028
1029 if (pop2) { /* a current msg */
1030 rmsgs++; /* mark this one as read */
1031 if (++pop2 > nmsgs)
1032 pop2 = -1; /* let rdp2 reset */
1033 else if (Msgs[pop2].m_flags & MDELE)
1034 pop2 = -1; /* let rdp2 reset */
1035 if (pop2 > Msgs[0].m_last)
1036 Msgs[0].m_last = pop2;
1037 }
1038 return rdp2 (vec); /* vec = { "acks", 0 } */
1039 }
1040
1041 static int fold (vec)
1042 register char **vec;
1043 {
1044 pop2 = 0;
1045
1046 #ifdef notdef
1047
1048 /* This might work, or it might be a huge security hole. For my purpose,
1049 * it doesn't need to work, so I'm not going to make sure it's OK.
1050 * 16Nov90/JLR
1051 */
1052
1053 if (quitaux (NULLVP) == NOTOK)
1054 return respond ('#', "0 unable to close folder");
1055
1056 (void) sprintf (maildrop, vec[1]);
1057 if (setupaux (access (maildrop, 2) ? 1 : 0) == NOTOK)
1058 return respond ('#', "0 unable to read %s", maildrop);
1059
1060 pop2 = nmsgs > 0 ? 1 : 0;
1061 return respond ('#', "%d message%s in %s (%d octets)",
1062 nmsgs, nmsgs != 1 ? "s" : "", maildrop, Msgs[0].m_size);
1063
1064 #endif
1065
1066 respond ('#', "0 unable to change folders");
1067 return NOTOK;
1068 }
1069 #endif /* POP2 */
1070
1071 static int list (vec)
1072 register char **vec;
1073 {
1074 register int i;
1075
1076 if (vec[1]) {
1077 if ((i = atoi (vec[1])) <= 0 || i > nmsgs)
1078 return respond (NOTOK, "no such message: \"%s\"", vec[1]);
1079 if (Msgs[i].m_flags & MDELE)
1080 return respond (NOTOK, "message %d is deleted", i);
1081
1082 #ifndef BPOP
1083 return respond (OK, "%d %d", i, Msgs[i].m_size);
1084 #else /* BPOP */
1085 #ifdef MPOP
1086 if (nfs && !xtnded) {
1087 char *cp;
1088
1089 (void) fseek (dp, Msgs[i].m_start, 0);
1090
1091 switch (scan (dp, i, 0, nfs, 0, 0, 0,
1092 0, NULLCP, (long) Msgs[i].m_size, 0)) {
1093 case SCNMSG:
1094 case SCNENC:
1095 case SCNERR:
1096 if (cp = index (scanl, '\n'))
1097 *cp = NULL;
1098 return respond (OK, "%d %d #%s",
1099 i, Msgs[i].m_size, scanl);
1100
1101 case SCNEOF:
1102 return respond (OK, "%d %d #%*d empty",
1103 i, Msgs[i].m_size, DMAXFOLDER, i);
1104
1105 default:
1106 break;
1107 }
1108 }
1109 #endif /* MPOP */
1110 return respond (OK, xtnded ? "%d %d %d" : "%d %d",
1111 i, Msgs[i].m_size, Msgs[i].m_id);
1112 #endif /* BPOP */
1113 }
1114
1115 (void) respond (OK, "%d message%s (%d octets)",
1116 nmsgs - dmsgs, nmsgs - dmsgs != 1 ? "s" : "",
1117 Msgs[0].m_size);
1118 for (i = 1; i <= nmsgs; i++)
1119 if (!(Msgs[i].m_flags & MDELE)) {
1120 #ifndef BPOP
1121 multiline ("%d %d", i, Msgs[i].m_size);
1122 #else /* BPOP */
1123 #ifdef MPOP
1124 if (nfs && !xtnded) {
1125 char *cp;
1126
1127 (void) fseek (dp, Msgs[i].m_start, 0);
1128
1129 switch (scan (dp, i, 0, nfs, 0, 0, 0,
1130 0, NULLCP, (long) Msgs[i].m_size, 0)) {
1131 case SCNMSG:
1132 case SCNENC:
1133 case SCNERR:
1134 if (cp = index (scanl, '\n'))
1135 *cp = NULL;
1136 multiline ("%d %d #%s",
1137 i, Msgs[i].m_size, scanl);
1138 continue;
1139
1140 case SCNEOF:
1141 multiline ("%d %d #%*d empty",
1142 i, Msgs[i].m_size, DMAXFOLDER, i);
1143 continue;
1144
1145 default:
1146 break;
1147 }
1148 }
1149 #endif /* MPOP */
1150 multiline (xtnded ? "%d %d %d" : "%d %d",
1151 i, Msgs[i].m_size, Msgs[i].m_id);
1152 #endif /* BPOP */
1153 }
1154 multiend ();
1155
1156 return OK;
1157 }
1158
1159 /* \f */
1160
1161 static int retrieve (vec)
1162 register char **vec;
1163 {
1164 register int i;
1165 register long pos;
1166 register char *cp;
1167 char buffer[BUFSIZ];
1168
1169 #ifdef POP2
1170 if (pop2 == 0)
1171 return NOTOK;
1172 else if (pop2 == NOTOK) {
1173 #endif
1174 if ((i = atoi (vec[1])) <= 0 || i > nmsgs)
1175 return respond (NOTOK, "no such message: \"%s\"", vec[1]);
1176 if (Msgs[i].m_flags & MDELE)
1177 return respond (NOTOK, "message %d is deleted", i);
1178
1179 (void) respond (OK, "%d octets", Msgs[i].m_size);
1180 #ifdef POP2
1181 }
1182 else /* if called by pop2, vec = { "retr", 0 } */
1183 i = pop2;
1184 #endif
1185
1186 for ((void) fseek (dp, pos = Msgs[i].m_start, 0);
1187 fgets (buffer, sizeof buffer, dp) != NULL && pos < Msgs[i].m_stop;
1188 pos += (long) (cp - buffer + 1)) {
1189 if (*(cp = buffer + strlen (buffer) - 1) == '\n')
1190 *cp = 0;
1191 multiline ("%s", buffer);
1192 }
1193 #ifdef POP2
1194 if (pop2 == NOTOK) { /* then multiend */
1195 #endif
1196 multiend ();
1197
1198 if (i > Msgs[0].m_last) {
1199 Msgs[0].m_last = i;
1200 rmsgs++;
1201 }
1202 #ifdef POP2
1203 }
1204 #endif
1205
1206 return OK;
1207 }
1208
1209 /* \f */
1210
1211 static int delete (vec)
1212 register char **vec;
1213 {
1214 register int i;
1215
1216 if (Msgs[0].m_flags & MREAD)
1217 return respond (NOTOK, "maildrop is read-only");
1218
1219 if ((i = atoi (vec[1])) <= 0 || i > nmsgs)
1220 return respond (NOTOK, "no such message: \"%s\"", vec[1]);
1221 if (Msgs[i].m_flags & MDELE)
1222 return respond (NOTOK, "message %d is deleted", i);
1223
1224 Msgs[i].m_flags |= MDELE;
1225 Msgs[0].m_size -= Msgs[i].m_size;
1226 dmsgs++;
1227
1228 if (i > Msgs[0].m_last)
1229 Msgs[0].m_last = i;
1230
1231 return respond (OK, "message %d deleted (%d octets)", i, Msgs[i].m_size);
1232 }
1233
1234
1235 static int reset (vec)
1236 char **vec;
1237 {
1238 register int i;
1239
1240 for (i = 1; i <= nmsgs; i++)
1241 if (Msgs[i].m_flags & MDELE) {
1242 Msgs[i].m_flags &= ~MDELE;
1243 Msgs[0].m_size += Msgs[i].m_size;
1244 dmsgs--;
1245 }
1246
1247 Msgs[0].m_last = lastseen;
1248
1249 #ifdef MPOP
1250 #ifdef BPOP
1251 if (nfs) {
1252 if (scanl)
1253 free (scanl), scanl = NULL;
1254 free (nfs), nfs = NULL;
1255 }
1256 #endif
1257 #endif /* MPOP */
1258
1259 return status (vec);
1260 }
1261
1262 /* \f */
1263
1264 static int top (vec)
1265 register char **vec;
1266 {
1267 register int i,
1268 j,
1269 body,
1270 lines;
1271 register long pos;
1272 register char *cp;
1273 char buffer[BUFSIZ];
1274
1275 if ((i = atoi (vec[1])) <= 0 || i > nmsgs)
1276 return respond (NOTOK, "no such message: \"%s\"", vec[1]);
1277 if (Msgs[i].m_flags & MDELE)
1278 return respond (NOTOK, "message %d is deleted", i);
1279 if ((j = atoi (vec[2])) < 0)
1280 return respond (NOTOK, "bad number: \"%s\"", vec[2]);
1281
1282 (void) respond (OK, vec[0]);
1283
1284 body = lines = 0;
1285 for ((void) fseek (dp, pos = Msgs[i].m_start, 0);
1286 fgets (buffer, sizeof buffer, dp) != NULL && pos < Msgs[i].m_stop;
1287 pos += (long) (cp - buffer + 1)) {
1288 if (*(cp = buffer + strlen (buffer) - 1) == '\n')
1289 *cp = 0;
1290 if (body) {
1291 if (lines++ >= j)
1292 break;
1293 }
1294 else
1295 if (*buffer == 0)
1296 body++;
1297 multiline ("%s", buffer);
1298 }
1299 multiend ();
1300
1301 return OK;
1302 }
1303
1304 /* \f */
1305
1306 /* ARGSUSED */
1307
1308 static int last (vec)
1309 char **vec;
1310 {
1311 return respond (OK, "%d is the last msg seen", Msgs[0].m_last);
1312 }
1313
1314 /* \f */
1315
1316 #ifdef BPOP
1317 static int xtnd (vec)
1318 register char **vec;
1319 {
1320 make_lower (vec[1], vec[1]);
1321
1322 if (strcmp (vec[1], "bboards") == 0 || strcmp (vec[1], "archive") == 0)
1323 return xtnd1 (vec);
1324 if (strcmp (vec[1], "x-bboards") == 0)
1325 return xtnd2 (vec);
1326 #ifdef MPOP
1327 if (strcmp (vec[1], "scan") == 0)
1328 return xtnd3 (vec);
1329 #endif /* MPOP */
1330
1331 return respond (NOTOK, "unknown XTND command: \"%s\"", vec[1]);
1332 }
1333
1334
1335 static int xtnd1 (vec)
1336 register char **vec;
1337 {
1338 register struct bboard *bb;
1339
1340 if (vec[2]) {
1341 make_lower (vec[2], vec[2]);
1342 if ((bb = getbbaux (vec[2])) == NULL)
1343 return respond (NOTOK, "unknown BBoard: \"%s\"", vec[2]);
1344
1345 if (quitaux (NULLVP) == NOTOK)
1346 return NOTOK;
1347 (void) strcpy (maildrop,
1348 strcmp (vec[1], "bboards") ? bb -> bb_archive : bb -> bb_file);
1349 if (setupaux (TRUE) == NOTOK)
1350 return NOTOK;
1351 xtnded++;
1352 (void) respond (OK, "%s", vec[1]);
1353 multiline ("%s %d", bb -> bb_name, bb -> bb_maxima);
1354 }
1355 else {
1356 if (strcmp (vec[1], "bboards"))
1357 return respond (NOTOK, "too few arguments to XTND \"%s\"", vec[1]);
1358
1359 (void) respond (OK, "%s", vec[1]);
1360 for (bb = BBhead; bb; bb = bb -> bb_next) {
1361 getbbmax (bb);
1362 if (!(bb -> bb_flags & BB_INVIS))
1363 multiline ("%s %d", bb -> bb_name, bb -> bb_maxima);
1364 }
1365 while (bb = getbbaux (NULLCP))
1366 if (!(bb -> bb_flags & BB_INVIS))
1367 multiline ("%s %d", bb -> bb_name, bb -> bb_maxima);
1368 }
1369 multiend ();
1370
1371 return OK;
1372 }
1373
1374 /* \f */
1375
1376 static int xtnd2 (vec)
1377 register char **vec;
1378 {
1379 register char *cp,
1380 **ap;
1381 char buffer[BUFSIZ];
1382 register struct bboard *bb;
1383
1384 if (vec[2] == NULL)
1385 return respond (NOTOK, "too few arguments to XTND \"%s\"", vec[1]);
1386
1387 make_lower (vec[2], vec[2]);
1388 if ((bb = getbbaux (vec[2])) == NULL)
1389 return respond (NOTOK, "unknown BBoard: \"%s\"", vec[2]);
1390
1391 (void) respond (OK, "%s", vec[1]);
1392 multiline ("%s", bb -> bb_name);
1393
1394 cp = buffer;
1395 for (ap = bb -> bb_aka; *ap; ap++) {
1396 (void) sprintf (cp, cp != buffer ? " %s" : "%s", *ap);
1397 cp += strlen (cp);
1398 }
1399 multiline ("%s", buffer);
1400
1401 multiline ("%s", bb -> bb_file);
1402 multiline ("%s", bb -> bb_archive);
1403 multiline ("%s", bb -> bb_info);
1404 multiline ("%s", bb -> bb_map);
1405 multiline ("%s", bb -> bb_passwd);
1406
1407 cp = buffer;
1408 for (ap = bb -> bb_leader; *ap; ap++) {
1409 (void) sprintf (cp, cp != buffer ? " %s" : "%s", *ap);
1410 cp += strlen (cp);
1411 }
1412 multiline ("%s", buffer);
1413
1414 multiline ("%s", bb -> bb_addr);
1415 multiline ("%s", bb -> bb_request);
1416 multiline ("%s", bb -> bb_relay);
1417
1418 cp = buffer;
1419 for (ap = bb -> bb_dist; *ap; ap++) {
1420 (void) sprintf (cp, cp != buffer ? " %s" : "%s", *ap);
1421 cp += strlen (cp);
1422 }
1423 multiline ("%s", buffer);
1424
1425 getbbmax (bb);
1426 multiline ("0%o %d", bb -> bb_flags, bb -> bb_maxima);
1427 multiline ("%s", bb -> bb_date);
1428
1429 multiend ();
1430
1431 return OK;
1432 }
1433
1434 /* \f */
1435
1436 static struct bboard *getbbaux (s)
1437 register char *s;
1438 {
1439 register struct bboard *bb;
1440 struct stat st;
1441
1442 if (BBhead == NULL)
1443 if (setbbinfo (BBOARDS, BBDB, 1))
1444 BBtime = getbbtime ();
1445 else
1446 return NULL;
1447
1448 if (s != NULLCP)
1449 for (bb = BBhead; bb; bb = bb -> bb_next)
1450 if (strcmp (bb -> bb_name, s) == 0) {
1451 if (debug)
1452 padvise (NULLCP, LOG_DEBUG, "getbbaux: \"%s\" from cache",
1453 bb -> bb_name);
1454 getbbmax (bb);
1455 return bb;
1456 }
1457
1458 while (bb = getbbent ()) {
1459 if ((bb = getbbcpy (bb)) == NULL)
1460 return NULL;
1461
1462 if (access (bb -> bb_file, 04) == NOTOK && errno == EACCES)
1463 bb -> bb_flags |= BB_INVIS;
1464 bb -> bb_mtime = stat (bb -> bb_info, &st) != NOTOK ? st.st_mtime : 0L;
1465
1466 if (BBtail != NULL)
1467 BBtail -> bb_next = bb;
1468 if (BBhead == NULL)
1469 BBhead = bb;
1470 BBtail = bb;
1471
1472 if (s == NULL || strcmp (bb -> bb_name, s) == 0) {
1473 if (s && debug)
1474 padvise (NULLCP, LOG_DEBUG, "getbbaux: \"%s\" from scratch",
1475 bb -> bb_name);
1476 return bb;
1477 }
1478 }
1479
1480 return NULL;
1481 }
1482
1483 /* \f */
1484
1485 static getbbmax (bb)
1486 register struct bboard *bb;
1487 {
1488 int i;
1489 register char *cp;
1490 char buffer[BUFSIZ];
1491 struct stat st;
1492 register FILE * fp;
1493
1494 if (debug)
1495 padvise (NULLCP, LOG_DEBUG, "getbbmax: \"%s\", 0%o, %d, %s",
1496 bb -> bb_name, bb -> bb_flags, bb -> bb_maxima, bb -> bb_date);
1497
1498 if (!(bb -> bb_flags & BB_INVIS)
1499 && access (bb -> bb_file, 04) == NOTOK && errno == EACCES)
1500 bb -> bb_flags |= BB_INVIS;
1501
1502 if (stat (bb -> bb_info, &st) == NOTOK
1503 || bb -> bb_mtime == st.st_mtime
1504 || (fp = fopen (bb -> bb_info, "r")) == NULL)
1505 return;
1506 bb -> bb_mtime = st.st_mtime;
1507
1508 if (fgets (buffer, sizeof buffer, fp) && (i = atoi (buffer)) > 0)
1509 bb -> bb_maxima = i;
1510 if (!feof (fp) && fgets (buffer, sizeof buffer, fp)) {
1511 if (bb -> bb_date)
1512 free (bb -> bb_date);
1513 if (cp = index (buffer, '\n'))
1514 *cp = NULL;
1515 bb -> bb_date = getcpy (buffer);
1516 }
1517
1518 (void) fclose (fp);
1519
1520 if (debug)
1521 padvise (NULLCP, LOG_DEBUG, "updated: \"%s\", 0%o, %d, %s",
1522 bb -> bb_name, bb -> bb_flags, bb -> bb_maxima, bb -> bb_date);
1523 }
1524
1525 /* \f */
1526
1527 #ifdef MPOP
1528 static int xtnd3 (vec)
1529 register char **vec;
1530 {
1531 if (vec[2] == NULL)
1532 return respond (NOTOK, "too few arguments to XTND \"%s\"", vec[1]);
1533 if ((_sc_width = atoi (vec[2])) < WIDTH / 2)
1534 _sc_width = WIDTH / 2;
1535 nfs = new_fs (NULLCP, vec[3], FORMAT);
1536 if (scanl)
1537 (void) free (scanl), scanl = NULL;
1538
1539 return respond (OK, vec[1]);
1540 }
1541
1542 int sc_width () { return _sc_width; }
1543 #endif /* MPOP */
1544 #endif /* BPOP */
1545
1546 /* \f */
1547
1548 static int quit (vec)
1549 char **vec;
1550 {
1551 int d,
1552 n;
1553
1554 d = dmsgs, n = nmsgs;
1555
1556 if (quitaux (vec) == NOTOK)
1557 return NOTOK;
1558
1559 #ifdef BPOP
1560 if (xtnded)
1561 return respond (OK, "%s signing off", server);
1562 #endif /* BPOP */
1563
1564 if (n == d)
1565 return respond (OK, "%s signing off (maildrop empty)", server);
1566
1567 return respond (OK,
1568 n ? "%s signing off (%d message%s, %d octets left)"
1569 : "%s signing off (maildrop empty)",
1570 server, n - d, n - d != 1 ? "s" : "", Msgs[0].m_size);
1571 }
1572
1573
1574 static int quitaux (vec)
1575 char **vec;
1576 {
1577 int i;
1578
1579 if (dp == NULL)
1580 return OK;
1581
1582 i = quitfile (vec);
1583
1584 nmsgs = dmsgs = rmsgs = 0;
1585 (void) lkfclose (dp, maildrop);
1586 dp = NULL;
1587
1588 return i;
1589 }
1590
1591 /* \f */
1592
1593 /* ARGSUSED */
1594
1595 static int quitfile (vec)
1596 char **vec;
1597 {
1598 register int i,
1599 j,
1600 tmpDR,
1601 md;
1602 char tmpfil[BUFSIZ],
1603 map1[BUFSIZ],
1604 map2[BUFSIZ];
1605 struct stat st;
1606
1607 if(debug)padvise(NULLCP,LOG_DEBUG,"XXX: dmsgs=%d rmsgs=%d readonly=%d",
1608 dmsgs, rmsgs, Msgs[0].m_flags & MREAD);
1609
1610 if (dmsgs == 0 || (Msgs[0].m_flags & MREAD))
1611 return OK;
1612
1613 if (fstat (fileno (dp), &st) == NOTOK)
1614 return respond (NOTOK, "unable to stat file");
1615 if (mtime != st.st_mtime)
1616 return respond (NOTOK, "new messages have arrived, no update");
1617 mode = (int) (st.st_mode & 0777);
1618
1619 if (nmsgs == dmsgs) {
1620 #ifndef SYS5
1621 i = truncate (maildrop, 0);
1622 #else /* SYS5 */
1623 i = open (maildrop, O_WRONLY | O_TRUNC);
1624 if (i != NOTOK) (void) close (i);
1625 #endif /* SYS5 */
1626 (void) unlink (map_name (maildrop));/* XXX */
1627 if (i == NOTOK)
1628 return respond (NOTOK, "unable to zero %s", maildrop);
1629 return OK;
1630 }
1631
1632 (void) strcpy (tmpfil, m_backup (maildrop));
1633 if ((md = mbx_open (tmpfil, st.st_uid, st.st_gid, mode)) == NOTOK)
1634 { char msgbuf0[256];
1635 sprintf(msgbuf0,"unable to create temporary file (%s)",tmpfil);
1636 return respond (NOTOK, msgbuf0);
1637 }
1638
1639 j = 0, tmpDR = Msgs[0].m_last;
1640 if(debug)padvise(NULLCP,LOG_DEBUG,"XXX: last=%d",Msgs[0].m_last);
1641 for (i = 1; i <= nmsgs; i++) {
1642 if (!(Msgs[i].m_flags & MDELE))
1643 j++;
1644 if (i == tmpDR)
1645 Msgs[0].m_last = j;
1646 }
1647 if(debug)padvise(NULLCP,LOG_DEBUG,"XXX: last=%d",Msgs[0].m_last);
1648
1649 for (i = 1; i <= nmsgs; i++)
1650 if (!(Msgs[i].m_flags & MDELE)
1651 && mbx_write (tmpfil, md, dp, Msgs[i].m_id, Msgs[0].m_last,
1652 Msgs[i].m_start, Msgs[i].m_stop, TRUE, debug)
1653 == NOTOK) {
1654 (void) mbx_close (tmpfil, md);
1655 (void) unlink (tmpfil);
1656 return respond (NOTOK, "error writing temporary file");
1657 }
1658 (void) mbx_close (tmpfil, md);
1659
1660 if ((i = rename (tmpfil, maildrop)) == OK) {
1661 (void) strcpy (map1, map_name (tmpfil));
1662 (void) strcpy (map2, map_name (maildrop));
1663 if (rename (map1, map2) == NOTOK) {
1664 (void) unlink (map1);
1665 (void) unlink (map2);
1666 }
1667 }
1668
1669 if (i == NOTOK)
1670 return respond (NOTOK, "unable to rename maildrop");
1671
1672 return OK;
1673 }
1674
1675 /* \f */
1676
1677 static struct vector *getvector (bp, vec)
1678 register char *bp,
1679 **vec;
1680 {
1681 register int i;
1682 register struct vector *v;
1683
1684 for (i = 0; i < NVEC; i++) {
1685 while (isspace (*bp))
1686 *bp++ = 0;
1687 if (*bp == 0) {
1688 vec[i] = NULL;
1689 break;
1690 }
1691
1692 if (*bp == '"') {
1693 for (vec[i] = ++bp; *bp != '\0' && *bp != '"'; bp++)
1694 if (*bp == '\\') {
1695 switch (*++bp) {
1696 case 'n':
1697 (void) strcpy (bp, bp + 1);
1698 *--bp = '\n';
1699 break;
1700
1701 case '\\':
1702 case '"':
1703 (void) strcpy (bp - 1, bp);
1704 /* and fall... */
1705 default:
1706 bp--;
1707 break;
1708 }
1709 }
1710 if (*bp == '"')
1711 *bp++ = '\0';
1712 continue;
1713 }
1714
1715 vec[i] = bp;
1716 while (!isspace (*bp))
1717 bp++;
1718 }
1719 i--;
1720 vec[NVEC] = NULL;
1721
1722 if (*bp != 0) {
1723 (void) respond (NOTOK, "too many arguments");
1724 return NULL;
1725 }
1726 if (*vec[0] == 0) {
1727 (void) respond (NOTOK, "null command");
1728 return NULL;
1729 }
1730 make_lower (vec[0], vec[0]);
1731
1732 for (v = vectors; v -> v_cmd; v++)
1733 if (strcmp (v -> v_cmd, vec[0]) == 0 && v -> v_valid == mystate) {
1734 if (i < v -> v_min || v -> v_max < i) {
1735 (void) respond (NOTOK, "too %s arguments to \"%s\"",
1736 i < v -> v_min ? "few" : "many", vec[0]);
1737 return NULL;
1738 }
1739 else
1740 return v;
1741 }
1742
1743 (void) respond (NOTOK, "unknown command: \"%s\"", vec[0]);
1744 return NULL;
1745 }
1746
1747 /* \f */
1748
1749 /* VARARGS2 */
1750
1751 static int respond (code, fmt, a, b, c, d)
1752 char *fmt,
1753 *a,
1754 *b,
1755 *c,
1756 *d;
1757 int code;
1758 {
1759 register char *bp;
1760 char buffer[BUFSIZ];
1761
1762 bp = buffer;
1763 #ifndef POP2
1764 (void) sprintf (bp, "%s%s", code == OK ? "+OK" : "-ERR", fmt ? " " : "");
1765 bp += strlen (bp);
1766 #else
1767 switch (code) {
1768 case OK:
1769 case NOTOK:
1770 (void) sprintf (bp, "%s%s", code == OK ? "+OK" : "-ERR",
1771 fmt ? " " : "");
1772 bp += strlen (bp);
1773 break;
1774
1775 default: /* only happens in pop2 */
1776 *bp++ = code;
1777 code = OK;
1778 }
1779 #endif
1780 if (fmt) {
1781 (void) sprintf (bp, fmt, a, b, c, d);
1782 bp += strlen (bp);
1783 }
1784 putline (buffer, output);
1785
1786 return code;
1787 }
1788
1789
1790 /* VARARGS1 */
1791
1792 static multiline (fmt, a, b, c, d)
1793 char *fmt,
1794 *a,
1795 *b,
1796 *c,
1797 *d;
1798 {
1799 register char *cp;
1800 char buffer[BUFSIZ + TRMLEN];
1801
1802 (void) strcpy (buffer, TRM);
1803 (void) sprintf (cp = (buffer + TRMLEN), fmt, a, b, c, d);
1804 if (strncmp (cp, TRM, TRMLEN) == 0)
1805 cp = buffer;
1806
1807 putline (cp, output);
1808 }
1809
1810
1811 static multiend () {
1812 putline (TRM, output);
1813 }
1814
1815 /* \f */
1816
1817 static int getline (s, n, iop)
1818 register char *s;
1819 register int n;
1820 register FILE *iop;
1821 {
1822 register int c;
1823 register char *p;
1824
1825 p = s;
1826 while (--n > 0 && (c = fgetc (iop)) != EOF) {
1827 while (c == IAC) {
1828 (void) fgetc (iop);
1829 c = fgetc (iop);
1830 }
1831 if ((*p++ = c) == '\n')
1832 break;
1833 }
1834 if (ferror (iop))
1835 return NOTOK;
1836 if (c == EOF && p == s)
1837 return DONE;
1838 if (debug) {
1839 if (*--p == '\n')
1840 *p = 0;
1841 padvise (NULLCP, LOG_DEBUG, "<--- %s", s);
1842 if (*p == 0)
1843 *p = '\n';
1844 p++;
1845 }
1846 *p++ = 0;
1847
1848 return OK;
1849 }
1850
1851
1852 static putline (s, iop)
1853 register char *s;
1854 register FILE *iop;
1855 {
1856 (void) fprintf (iop, "%s\r\n", s);
1857 if (debug)
1858 padvise (NULLCP, LOG_DEBUG, "---> %s", s);
1859
1860 (void) fflush (iop);
1861 }
1862
1863
1864 /* ARGSUSED */
1865
1866 static TYPESIG pipeser (sig, code, sc)
1867 int sig;
1868 long code;
1869 struct sigcontext *sc;
1870 {
1871 padvise (NULLCP, LOG_WARNING, "lost connection");
1872
1873 _exit (NOTOK);
1874 }
1875
1876 /* \f */
1877
1878 /* Some people don't want to use the POP delivery agent with Sendmail
1879 * if they're going to run POP. Sendmail writes maildrops in the old
1880 * UUCP format, and popd doesn't know how to read them. These people
1881 * really should do what the MH manual says -- run the pop delivery
1882 * agent and be done with it. Some things never die.
1883 *
1884 * A real fix would be to make uip/dropsbr.c should use the same methods
1885 * as sbr/m_getfld.c to determine the format of maildrops and read &
1886 * write them. Unfortunately, it'll take a lot of work to bring it into
1887 * the fold. 20Mar90/JLR
1888 *
1889 * I really really hate to add this, but this lets stuff popd read
1890 * UUCP style maildrops as well as MMDF (ctrl/A) style maildrops. It was
1891 * contributed by Steve Dempsey <steved@longs.LANCE.ColoState.Edu>.
1892 *
1893 * Here's what he says:
1894 *
1895 * Ideally, one should be able to do it with the mmdelim strings, but
1896 * the MH parser is not intelligent enough to do this. You have at
1897 * least a couple of choices:
1898 *
1899 * - use aliases to deliver mail to POP users (user: user@pop) and
1900 * install the POP delivery agent - should work well with sendmail.
1901 * - fix the POP server!
1902 *
1903 * We have all mail sent to one machine and users are given two options:
1904 *
1905 * - MH on any machine.
1906 * - any user agent on the postoffice machine.
1907 *
1908 * Most of our workstations run xmh and users find that to be sufficient.
1909 * New users are only taught to use MH, and a very few old timers stay
1910 * with BSD mail. In any case, several agents are available at the cost
1911 * of a telnet/rlogin if a user does not like MH.
1912 *
1913 * I have made the changes to the POP server (MH-6.6/support/pop/popser.c)
1914 * to look for the `\n\nFrom ' delimiter instead of the ^A's, using some
1915 * code from the BSD agent. Context diff is included below. When this
1916 * is installed, you just go back to the normal localmail and get rid of
1917 * slocal completely.
1918 *
1919 * I have not tried this modification with anything but the MH client,
1920 * but it should work. Nothing in the POP protocol changes; the server
1921 * just has different criteria for delimiting messages in the mailbox.
1922 * If you decide to use this, I'd like to know what happens.
1923 *
1924 * Steve Dempsey, Center for Computer Assisted Engineering
1925 * Colorado State University, Fort Collins, CO 80523 +1 303 491 0630
1926 * INET: steved@longs.LANCE.ColoState.Edu, dempsey@handel.CS.ColoState.Edu
1927 * boulder!ccncsu!longs.LANCE.ColoState.Edu!steved, ...!ncar!handel!dempsey
1928 */
1929 /* From: Jim Reid <jim@computer-science.strathclyde.ac.UK>
1930 *
1931 * MH-6.7 does not support MMDF-style mailboxes with POP as claimed. It
1932 * appears that when code was added to popser.c to support UNIX-style
1933 * mailboxes, the old behaviour was lost. i.e. The new popd worked with
1934 * UNIX-style mailboxes, but not MMDF ones. Users would get "format error"
1935 * error messages if they tried to inc a remote MMDF-style mailbox because
1936 * the pop daemon didn't want to know or like the MMDF message delimiters.
1937 */
1938
1939 /* So... Now there's an incredible hack in mhconfig.c to define POPUUMBOX
1940 * in support/pop/Makefile if we're using Sendmail. This causes this
1941 * UUCP-mbox reading code to be used here. Ugh. 05Nov90/JLR
1942 */
1943
1944 /* \f */
1945 #ifdef POPUUMBOX
1946 /* from dropsbr.c - read from a mailbox - pop server version */
1947
1948 /* ALMOST IDENTICAL to mbx_read */
1949
1950 static int pmbx_read (fp, pos, drops, noisy)
1951 register FILE *fp;
1952 register long pos;
1953 struct drop **drops;
1954 int noisy;
1955 {
1956 register int len,
1957 size;
1958 register char *bp;
1959 char buffer[BUFSIZ];
1960 register struct drop *cp,
1961 *dp,
1962 *ep,
1963 *pp;
1964
1965 /* MTR: tsk, tsk, tsk... */
1966 (void) fseek (fp, pos, 0);
1967 if (fgets (buffer, sizeof buffer, fp)
1968 && strcmp (buffer, mmdlm1) == 0)
1969 return mbx_read (fp, pos, drops, noisy);
1970
1971 /* get drop storage */
1972 pp = (struct drop *) calloc ((unsigned) (len = MAXFOLDER), sizeof *dp);
1973
1974 if (debug)
1975 padvise (NULLCP, LOG_DEBUG, "pmbx_read (%d, %ld, %d, %d)",
1976 fp, pos,drops,noisy);
1977
1978 if (pp == NULL) {
1979 if (noisy)
1980 admonish (NULLCP, "unable to allocate drop storage");
1981 return NOTOK;
1982 }
1983
1984 /* rewind drop file */
1985 (void) fseek (fp, pos, 0);
1986
1987 if (debug)
1988 padvise (NULLCP, LOG_DEBUG, "rewind maildrop");
1989
1990 /* read a buffer */
1991 for (ep = (dp = pp) + len - 1; fgets (buffer, sizeof buffer, fp);) {
1992 size = 0;
1993
1994 /* if beginning of msg then mark it */
1995
1996 if (p_ishead(buffer)) /*(strcmp (buffer, mmdlm1) == 0)*/ {
1997 /* (don't) inc pos to msg start, mark it */
1998 /*pos += ld1;*/
1999 dp -> d_start = pos;
2000 pos += strlen(buffer); /* inc pos after marking head */
2001 }
2002 else {
2003 /* didn't find it; mark it anyway */
2004 dp -> d_start = pos, pos += (long) strlen (buffer);
2005
2006 /* count newlines and inc size if any found */
2007 for (bp = buffer; *bp; bp++, size++)
2008 if (*bp == '\n')
2009 size++;
2010 }
2011
2012 /* read more lines... */
2013 while (fgets (buffer, sizeof buffer, fp) != NULL)
2014
2015 /* found end? */
2016 if (p_ishead(buffer)) /*(strcmp (buffer, mmdlm2) == 0)*/ {
2017
2018 /* out of loop */
2019 (void) fseek (fp, pos, 0);
2020 break;
2021
2022 }
2023 else {
2024 /* add buffer size to pos */
2025 pos += (long) strlen (buffer);
2026
2027 /* count newlines.... */
2028 for (bp = buffer; *bp; bp++, size++)
2029 if (*bp == '\n')
2030 size++;
2031 }
2032
2033 if (dp -> d_start != pos) {
2034 /* do this if pos was actually incremented; got some text */
2035 dp -> d_id = 0;
2036 dp -> d_size = size; /* save the stuff we got */
2037 dp -> d_stop = pos;
2038 dp++;
2039 }
2040
2041 /* (don't) advance pos */
2042 /* pos += ld2; */
2043
2044 /* need more storage.... */
2045 if (dp >= ep) {
2046 register int curlen = dp - pp;
2047
2048 cp = (struct drop *) realloc ((char *) pp,
2049 (unsigned) (len += MAXFOLDER) * sizeof *pp);
2050 if (cp == NULL) {
2051 if (noisy)
2052 admonish (NULLCP, "unable to allocate drop storage");
2053 free ((char *) pp);
2054 return 0;
2055 }
2056 dp = cp + curlen, ep = (pp = cp) + len - 1;
2057 }
2058 }
2059
2060 /* return unused stuff */
2061 if (dp == pp)
2062 free ((char *) pp);
2063 else
2064 *drops = pp;
2065 return (dp - pp);
2066 }
2067
2068 /*
2069 * The remainder of this file adapted from:
2070 *
2071 * head.c 5.2 (Berkeley) 6/21/85
2072 */
2073
2074 struct p_hdline {
2075 char *l_from; /* The name of the sender */
2076 char *l_tty; /* His tty string (if any) */
2077 char *l_date; /* The entire date string */
2078 };
2079
2080 /*
2081 *
2082 * See if position in a file is a mail header.
2083 * Return true if yes. Note the extreme pains to
2084 * accomodate all funny formats.
2085 */
2086
2087 #define NOSTR ((char *) 0) /* Null string pointer */
2088 static char *p_copyin();
2089 static char *p_copy();
2090
2091
2092 static p_ishead(buffer)
2093 char buffer[];
2094 {
2095 register char *cp;
2096 struct p_hdline hl;
2097 char linebuf[BUFSIZ];
2098 char parbuf[BUFSIZ];
2099
2100 strcpy(linebuf,buffer);
2101 cp = linebuf;
2102
2103 if (linebuf[0]=='F')
2104 padvise (NULLCP, LOG_DEBUG, "ishead: '%s'",linebuf);
2105
2106 if (strncmp("From ", cp, 5) != 0)
2107 return(0);
2108
2109 padvise (NULLCP, LOG_DEBUG, "Fromline...");
2110
2111 /* get full header */
2112 p_parse(cp, &hl, parbuf);
2113
2114 if (hl.l_from == NOSTR || hl.l_date == NOSTR) {
2115 padvise (NULLCP, LOG_DEBUG, "Fromline...NODATE");
2116 return(0);
2117 }
2118
2119 if (!p_isdate(hl.l_date)) {
2120 padvise (NULLCP, LOG_DEBUG, "Fromline...BADDATE %s",
2121 hl.l_date);
2122 return(0);
2123 }
2124
2125 /* I guess we got it! */
2126 padvise (NULLCP, LOG_DEBUG, "got a head.. ");
2127
2128 return(1);
2129 }
2130
2131 /*
2132 * Split a headline into its useful components.
2133 * Copy the line into dynamic string space, then set
2134 * pointers into the copied line in the passed headline
2135 * structure. Actually, it scans.
2136 */
2137
2138 static p_parse(line, hl, pbuf)
2139 char line[], pbuf[];
2140 struct p_hdline *hl;
2141 {
2142 register char *cp, *dp;
2143 char *sp;
2144 char word[BUFSIZ];
2145 char * p_nextword();
2146
2147 hl->l_from = NOSTR;
2148 hl->l_tty = NOSTR;
2149 hl->l_date = NOSTR;
2150 cp = line;
2151 sp = pbuf;
2152
2153 /*
2154 * Skip the first "word" of the line, which should be "From"
2155 * anyway.
2156 */
2157 cp = p_nextword(cp, word);
2158 dp = p_nextword(cp, word);
2159 if (!(strcmp(word, "")==0))
2160 hl->l_from = p_copyin(word, &sp);
2161
2162 /* UNLIKELY */
2163 if (strncmp(dp, "tty", 3) == 0) {
2164 cp = p_nextword(dp, word);
2165 hl->l_tty = p_copyin(word, &sp);
2166 if (cp != NOSTR)
2167 hl->l_date = p_copyin(cp, &sp);
2168 }
2169
2170 /* USUAL */
2171 else
2172 if (dp != NOSTR)
2173 hl->l_date = p_copyin(dp, &sp);
2174 }
2175
2176 /*
2177 * Copy the string on the left into the string on the right
2178 * and bump the right (reference) string pointer by the length.
2179 * Thus, dynamically allocate space in the right string, copying
2180 * the left string into it.
2181 */
2182
2183 static char *
2184 p_copyin(src, space)
2185 char src[];
2186 char **space;
2187 {
2188 register char *cp, *top;
2189 register int s;
2190
2191 s = strlen(src);
2192 cp = *space;
2193 top = cp;
2194 strcpy(cp, src);
2195 cp += s + 1;
2196 *space = cp;
2197 return(top);
2198 }
2199
2200 /*
2201 * Collect a liberal (space, tab delimited) word into the word buffer
2202 * passed. Also, return a pointer to the next word following that,
2203 * or (empty) if none follow.
2204 */
2205
2206 static char *
2207 p_nextword(wp, wbuf)
2208 char wp[], wbuf[];
2209 {
2210 register char *cp, *cp2;
2211
2212 if ((cp = wp) == NOSTR) {
2213 p_copy("", wbuf);
2214 return(NOSTR);
2215 }
2216 cp2 = wbuf;
2217 while (!any(*cp, " \t") && *cp != '\0')
2218 if (*cp == '"') {
2219 *cp2++ = *cp++;
2220 while (*cp != '\0' && *cp != '"')
2221 *cp2++ = *cp++;
2222 if (*cp == '"')
2223 *cp2++ = *cp++;
2224 } else
2225 *cp2++ = *cp++;
2226 *cp2 = '\0';
2227 while (any(*cp, " \t"))
2228 cp++;
2229 if (*cp == '\0')
2230 return(NOSTR);
2231 return(cp);
2232 }
2233
2234 /*
2235 * Copy str1 to str2, return pointer to null in str2.
2236 */
2237
2238 static char *
2239 p_copy(str1, str2)
2240 char *str1, *str2;
2241 {
2242 register char *s1, *s2;
2243
2244 s1 = str1;
2245 s2 = str2;
2246 while (*s1)
2247 *s2++ = *s1++;
2248 *s2 = 0;
2249 return(s2);
2250 }
2251
2252 #define L 1 /* A lower case char */
2253 #define S 2 /* A space */
2254 #define D 3 /* A digit */
2255 #define O 4 /* An optional digit or space */
2256 #define C 5 /* A colon */
2257 #define N 6 /* A new line */
2258 #define U 7 /* An upper case char */
2259
2260 static char p_ctypes[] =
2261 {U,L,L,S,U,L,L,S,O,D,S,D,D,C,D,D,C,D,D,S,D,D,D,D,0};
2262 /* T h u S e p 2 9 1 5 : 2 0 : 1 9 1 9 8 8 */
2263
2264 static char p_tmztyp[] =
2265 {U,L,L,S,U,L,L,S,O,D,S,D,D,C,D,D,C,D,D,S,U,U,U,S,D,D,D,D,0};
2266 /* T h u S e p 2 9 1 5 : 2 0 : 1 9 M S T 1 9 8 8 */
2267
2268 static p_isdate(date)
2269 char date[];
2270 {
2271 register char *cp;
2272
2273 cp = date;
2274 if (p_cmatch(cp, p_ctypes))
2275 return(1);
2276
2277 return(p_cmatch(cp, p_tmztyp));
2278 }
2279
2280 /*
2281 * Match the given string against the given template.
2282 * Return 1 if they match, 0 if they don't
2283 */
2284
2285 static p_cmatch(str, temp)
2286 char str[], temp[];
2287 {
2288 register char *cp, *tp;
2289 register int c;
2290
2291 cp = str;
2292 tp = temp;
2293 while (*cp != '\0' && *tp != 0) {
2294 c = *cp++;
2295 switch (*tp++) {
2296 case L:
2297 if (c < 'a' || c > 'z')
2298 return(0);
2299 break;
2300
2301 case U:
2302 if (c < 'A' || c > 'Z')
2303 return(0);
2304 break;
2305
2306 case S:
2307 if (c != ' ')
2308 return(0);
2309 break;
2310
2311 case D:
2312 if (!isdigit(c))
2313 return(0);
2314 break;
2315
2316 case O:
2317 if (c != ' ' && !isdigit(c))
2318 return(0);
2319 break;
2320
2321 case C:
2322 if (c != ':')
2323 return(0);
2324 break;
2325
2326 case N:
2327 if (c != '\n')
2328 return(0);
2329 break;
2330 }
2331 }
2332 if ((*cp != '\0' && *cp != '\n') || *tp != 0)
2333 return(0);
2334 return(1);
2335 }
2336
2337 static any(ch, str)
2338 char *str;
2339 {
2340 register char *f;
2341 register c;
2342
2343 f = str;
2344 c = ch;
2345 while (*f)
2346 if (c == *f++)
2347 return(1);
2348 return(0);
2349 }
2350 #endif