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