Mercurial > hg > Applications > mh
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 |