0
|
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
|