comparison support/pop/popser.c @ 0:bce86c4163a3

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