]> diplodocus.org Git - nmh/blob - docs/historical/mh-6.8.5/uip/popi.c
sbr/mts.c: Delete mmdlm2; use same-valued mmdlm1 instead.
[nmh] / docs / historical / mh-6.8.5 / uip / popi.c
1 /* popi.c - POP initiator - for MPOP */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: popi.c,v 1.8 1992/10/28 18:52:45 jromine Exp $";
4 #endif lint
5
6 #include "../h/mh.h"
7 #include "../h/formatsbr.h"
8 #include "../h/scansbr.h"
9 #include <errno.h>
10 #include <stdio.h>
11 #include <sys/types.h>
12 #ifdef SMTP
13 #include "../h/local.h"
14 #else /* SMTP */
15 #include <sys/stat.h>
16 #endif /* SMTP */
17 #include "../zotnet/mts.h"
18
19 /* \f */
20
21 #ifndef RPOP
22 #define RPOPminc(a) (a)
23 #else
24 #define RPOPminc(a) 0
25 #endif
26
27 #ifndef APOP
28 #define APOPminc(a) (a)
29 #else
30 #define APOPminc(a) 0
31 #endif
32
33 #ifndef BPOP
34 #define BPOPminc(a) (a)
35 #else
36 #define BPOPminc(a) 0
37 #endif
38
39 #ifndef SMTP
40 #define BULKminc(a) (a)
41 #else
42 #define BULKminc(a) 0
43 #endif
44
45 static struct swit switches[] = {
46 #define APOPSW 0
47 "apop", APOPminc (-4),
48 #define NAPOPSW 1
49 "noapop", APOPminc (-6),
50
51 #define AUTOSW 2
52 "auto", BPOPminc(-4),
53 #define NAUTOSW 3
54 "noauto", BPOPminc(-6),
55
56 #define BULKSW 4
57 "bulk directory", BULKminc(-4),
58
59 #define FORMSW 5
60 "form formatfile", 0,
61
62 #define FMTSW 6
63 "format string", 5,
64
65 #define HOSTSW 7
66 "host host", 0,
67
68 #define PROGSW 8
69 "mshproc program", 0,
70
71 #define RPOPSW 9
72 "rpop", RPOPminc (-4),
73 #define NRPOPSW 10
74 "norpop", RPOPminc (-6),
75
76 #define USERSW 11
77 "user user", 0,
78
79 #define WIDSW 12
80 "width columns", 0,
81
82 #define HELPSW 13
83 "help", 4,
84
85 NULL, 0
86 };
87
88 /* \f */
89
90 static char *bulksw = NULLCP;
91 static int snoop = 0;
92 static int width = 0;
93
94 static char mailname[BUFSIZ];
95
96 static char *nfs = NULL;
97
98 static struct msgs *mp;
99
100 extern int errno;
101
102 extern char response[];
103
104 /* \f */
105
106 /* ARGSUSED */
107
108 main (argc, argv)
109 int argc;
110 char *argv[];
111 {
112 int autosw = 1,
113 noisy = 1,
114 rpop;
115 char *cp,
116 *maildir,
117 *folder = NULL,
118 *form = NULL,
119 *format = NULL,
120 *host = NULL,
121 *user = NULL,
122 *pass = NULL,
123 buf[100],
124 **ap,
125 **argp,
126 *arguments[MAXARGS];
127 struct stat st;
128
129 invo_name = r1bindex (argv[0], '/');
130 mts_init (invo_name);
131 if (pophost && *pophost)
132 host = pophost;
133 if ((cp = getenv ("MHPOPDEBUG")) && *cp)
134 snoop++;
135 if ((cp = m_find (invo_name)) != NULL) {
136 ap = brkstring (cp = getcpy (cp), " ", "\n");
137 ap = copyip (ap, arguments);
138 }
139 else
140 ap = arguments;
141 (void) copyip (argv + 1, ap);
142 argp = arguments;
143
144 rpop = getuid () && !geteuid ();
145
146 /* \f */
147
148 while (cp = *argp++) {
149 if (*cp == '-')
150 switch (smatch (++cp, switches)) {
151 case AMBIGSW:
152 ambigsw (cp, switches);
153 done (1);
154 case UNKWNSW:
155 adios (NULLCP, "-%s unknown", cp);
156 case HELPSW:
157 (void) sprintf (buf, "%s [+folder] [switches]", invo_name);
158 help (buf, switches);
159 done (1);
160
161 case AUTOSW:
162 autosw = 1;
163 continue;
164 case NAUTOSW:
165 autosw = 0;
166 continue;
167
168 case BULKSW:
169 if (!(bulksw = *argp++) || *bulksw == '-')
170 adios (NULLCP, "missing argument to %s", argp[-2]);
171 continue;
172
173 case FORMSW:
174 if (!(form = *argp++) || *form == '-')
175 adios (NULLCP, "missing argument to %s", argp[-2]);
176 format = NULL;
177 continue;
178 case FMTSW:
179 if (!(format = *argp++) || *format == '-')
180 adios (NULLCP, "missing argument to %s", argp[-2]);
181 form = NULL;
182 continue;
183
184 case WIDSW:
185 if (!(cp = *argp++) || *cp == '-')
186 adios (NULLCP, "missing argument to %s", argp[-2]);
187 width = atoi (cp);
188 continue;
189
190 case HOSTSW:
191 if (!(host = *argp++) || *host == '-')
192 adios (NULLCP, "missing argument to %s", argp[-2]);
193 continue;
194 case USERSW:
195 if (!(user = *argp++) || *user == '-')
196 adios (NULLCP, "missing argument to %s", argp[-2]);
197 continue;
198
199 case APOPSW:
200 rpop = -1;
201 continue;
202 case RPOPSW:
203 rpop = 1;
204 continue;
205 case NAPOPSW:
206 case NRPOPSW:
207 rpop = 0;
208 continue;
209
210 case PROGSW:
211 if (!(mshproc = *argp++) || *mshproc == '-')
212 adios (NULLCP, "missing argument to %s", argp[-2]);
213 continue;
214 }
215 if (*cp == '+' || *cp == '@') {
216 if (folder)
217 adios (NULLCP, "only one folder at a time!");
218 else
219 folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
220 }
221 else
222 adios (NULLCP, "usage: %s [+folder] [switches]", invo_name);
223 }
224
225 /* \f */
226
227 if (!host)
228 adios (NULLCP, "usage: %s -host \"host\"", invo_name);
229
230 #ifdef SMTP
231 if (bulksw)
232 do_bulk (host);
233 #endif
234
235 if (user == NULL)
236 user = getusr ();
237 if (rpop > 0)
238 pass = getusr ();
239 else {
240 (void) setuid (getuid ());
241 ruserpass (host, &user, &pass);
242 }
243 (void) sprintf (mailname, "PO box for %s@%s", user, host);
244
245 if (pop_init (host, user, pass, snoop, rpop) == NOTOK)
246 adios (NULLCP, "%s", response);
247 if (rpop > 0)
248 (void) setuid (getuid ());
249
250 nfs = new_fs (form, format, FORMAT);
251
252 if (!m_find ("path"))
253 free (path ("./", TFOLDER));
254 if (!folder && !(folder = m_find (inbox)))
255 folder = defalt;
256 maildir = m_maildir (folder);
257
258 if (stat (maildir, &st) == NOTOK) {
259 if (errno != ENOENT)
260 adios (maildir, "error on folder");
261 cp = concat ("Create folder \"", maildir, "\"? ", NULLCP);
262 if (noisy && !getanswer (cp))
263 done (1);
264 free (cp);
265 if (!makedir (maildir))
266 adios (NULLCP, "unable to create folder %s", maildir);
267 }
268
269 if (chdir (maildir) == NOTOK)
270 adios (maildir, "unable to change directory to");
271 if (!(mp = m_gmsg (folder)))
272 adios (NULLCP, "unable to read folder %s", folder);
273
274 #ifdef BPOP
275 if (autosw)
276 msh ();
277 else
278 #endif
279 popi ();
280
281 (void) pop_quit ();
282
283 m_replace (pfolder, folder);
284 m_setvis (mp, 0);
285 m_sync (mp);
286 m_update ();
287
288 done (0);
289
290 /* NOTREACHED */
291 }
292
293 /* \f */
294
295 static struct swit popicmds[] = {
296 #define DELECMD 0
297 "dele", 0,
298 #define LASTCMD 1
299 "last", 0,
300 #define LISTCMD 2
301 "list", 0,
302 #define NOOPCMD 3
303 "noop", 0,
304 #define QUITCMD 4
305 "quit", 0,
306 #define RETRCMD 5
307 "retr", 0,
308 #define RSETCMD 6
309 "rset", 0,
310 #define SCANCMD 7
311 "scan", 0,
312 #define STATCMD 8
313 "stat", 0,
314 #define TOPCMD 9
315 "top", 0,
316 #ifdef BPOP
317 #define MSHCMD 10
318 "msh", 0,
319 #endif
320
321 NULL, 0
322 };
323
324 /* \f */
325
326 static popi ()
327 {
328 int eof;
329
330 eof = 0;
331 for (;;) {
332 int i;
333 register char *cp;
334 char buffer[BUFSIZ];
335
336 if (eof)
337 return;
338
339 printf ("(%s) ", invo_name);
340 for (cp = buffer; (i = getchar ()) != '\n'; ) {
341 if (i == EOF) {
342 (void) putchar ('\n');
343 if (cp == buffer)
344 return;
345 eof = 1;
346 break;
347 }
348
349 if (cp < buffer + sizeof buffer - 2)
350 *cp++ = i;
351 }
352 *cp = '\0';
353 if (buffer[0] == '\0')
354 continue;
355 if (buffer[0] == '?') {
356 printf ("commands:\n");
357 printsw (ALL, popicmds, "");
358 printf ("type CTRL-D or use \"quit\" to leave %s\n", invo_name);
359 continue;
360 }
361
362 if (cp = index (buffer, ' '))
363 *cp = '\0';
364 switch (i = smatch (buffer, popicmds)) {
365 case AMBIGSW:
366 ambigsw (buffer, popicmds);
367 continue;
368 case UNKWNSW:
369 printf ("%s unknown -- type \"?\" for help\n", buffer);
370 continue;
371
372 case QUITCMD:
373 return;
374
375 case STATCMD:
376 case DELECMD:
377 case NOOPCMD:
378 case LASTCMD:
379 case RSETCMD:
380 case TOPCMD:
381 if (cp)
382 *cp = ' ';
383 (void) pop_command ("%s%s", popicmds[i].sw, cp ? cp : "");
384 printf ("%s\n", response);
385 break;
386
387 case LISTCMD:
388 if (cp)
389 *cp = ' ';
390 if (pop_command ("%s%s", popicmds[i].sw, cp ? cp : "")
391 == OK) {
392 printf ("%s\n", response);
393 if (!cp)
394 for (;;) {
395 switch (pop_multiline ()) {
396 case DONE:
397 (void) strcpy (response, ".");
398 /* and fall... */
399 case NOTOK:
400 printf ("%s\n", response);
401 break;
402
403 case OK:
404 printf ("%s\n", response);
405 continue;
406 }
407 break;
408 }
409 }
410 break;
411
412 case RETRCMD:
413 if (!cp) {
414 advise (NULLCP, "missing argument to %s", buffer);
415 break;
416 }
417 retr_action (NULLCP, OK);
418 (void) pop_retr (atoi (++cp), retr_action);
419 retr_action (NULLCP, DONE);
420 printf ("%s\n", response);
421 break;
422
423 case SCANCMD:
424 {
425 char *dp,
426 *ep,
427 *fp;
428
429 if (width == 0)
430 width = sc_width ();
431
432 for (dp = nfs, i = 0; *dp; dp++, i++)
433 if (*dp == '\\' || *dp == '"' || *dp == '\n')
434 i++;
435 i++;
436 if ((ep = malloc ((unsigned) i)) == NULL)
437 adios (NULLCP, "out of memory");
438 for (dp = nfs, fp = ep; *dp; dp++) {
439 if (*dp == '\n') {
440 *fp++ = '\\', *fp++ = 'n';
441 continue;
442 }
443 if (*dp == '"' || *dp == '\\')
444 *fp++ = '\\';
445 *fp++ = *dp;
446 }
447 *fp = '\0';
448
449 (void) pop_command ("xtnd scan %d \"%s\"", width, ep);
450 printf ("%s\n", response);
451
452 free (ep);
453 }
454 break;
455
456 #ifdef BPOP
457 case MSHCMD:
458 msh ();
459 break;
460 #endif
461 }
462 }
463 }
464
465 /* \f */
466
467 static int retr_action (rsp, flag)
468 char *rsp;
469 int flag;
470 {
471 static FILE *fp;
472
473 if (rsp == NULL) {
474 static int msgnum;
475 static char *cp;
476
477 if (flag == OK) {
478 if ((mp = m_remsg (mp, 0, msgnum = mp -> hghmsg + 1)) == NULL)
479 adios (NULLCP, "unable to allocate folder storage");
480
481 cp = getcpy (m_name (mp -> hghmsg + 1));
482 if ((fp = fopen (cp, "w+")) == NULL)
483 adios (cp, "unable to write");
484 (void) chmod (cp, m_gmprot ());
485 }
486 else {
487 struct stat st;
488
489 (void) fflush (fp);
490 if (fstat (fileno (fp), &st) != NOTOK && st.st_size > 0) {
491 mp -> msgstats[msgnum] = EXISTS | UNSEEN;
492 mp -> msgflags |= SEQMOD;
493
494 if (ferror (fp))
495 advise (cp, "write error on");
496 mp -> hghmsg = msgnum;
497 }
498 else
499 (void) unlink (cp);
500
501 (void) fclose (fp), fp = NULL;
502 free (cp), cp = NULL;
503 }
504
505 return;
506 }
507
508 fprintf (fp, "%s\n", rsp);
509 }
510
511 /* \f */
512
513 #ifdef BPOP
514 static msh ()
515 {
516 int child_id,
517 vecp;
518 char buf1[BUFSIZ],
519 buf2[BUFSIZ],
520 *vec[9];
521
522 if (pop_fd (buf1, buf2) == NOTOK)
523 adios (NULLCP, "%s", response);
524
525 vecp = 0;
526 vec[vecp++] = r1bindex (mshproc, '/');
527
528 switch (child_id = fork ()) {
529 case NOTOK:
530 adios ("fork", "unable to");
531
532 case OK:
533 vec[vecp++] = "-popread";
534 vec[vecp++] = buf1;
535 vec[vecp++] = "-popwrite";
536 vec[vecp++] = buf2;
537 vec[vecp++] = "-idname";
538 vec[vecp++] = mailname;
539 vec[vecp++] = mailname;
540 vec[vecp] = NULL;
541 (void) execvp (mshproc, vec);
542 fprintf (stderr, "unable to exec ");
543 perror (mshproc);
544 _exit (-1);
545
546 default:
547 (void) pidXwait (child_id, mshproc);
548 break;
549 }
550 }
551 #endif
552
553 /* \f */
554
555 #ifdef SMTP
556 #include "../zotnet/mts.h"
557 #include "../mts/sendmail/smail.h"
558
559
560 static int dselect (d)
561 register struct direct *d;
562 {
563 int i;
564
565 if ((i = strlen (d -> d_name)) < sizeof "smtp"
566 || strncmp (d -> d_name, "smtp", sizeof "smtp" - 1))
567 return 0;
568 return ((i -= (sizeof ".bulk" - 1)) > 0
569 && !strcmp (d -> d_name + i, ".bulk"));
570 }
571
572
573 static int dcompar (d1, d2)
574 struct direct **d1,
575 **d2;
576 {
577 struct stat s1,
578 s2;
579
580 if (stat ((*d1) -> d_name, &s1) == NOTOK)
581 return 1;
582 if (stat ((*d2) -> d_name, &s2) == NOTOK)
583 return -1;
584 return ((int) (s1.st_mtime - s2.st_mtime));
585 }
586
587
588 static do_bulk (host)
589 char *host;
590 {
591 register int i;
592 int n,
593 retval,
594 sm;
595 struct direct **namelist;
596
597 if (chdir (bulksw) == NOTOK)
598 adios (bulksw, "unable to change directory to");
599
600 if ((n = scandir (".", &namelist, dselect, dcompar)) == NOTOK)
601 adios (bulksw, "unable to scan directory");
602
603 sm = NOTOK;
604 for (i = 0; i < n; i++) {
605 register struct direct *d = namelist[i];
606
607 if (sm == NOTOK) {
608 if (rp_isbad (retval = sm_init (NULLCP, host, 1, 1, snoop)))
609 adios (NULLCP, "problem initializing server: %s",
610 rp_string (retval));
611 else
612 sm = OK;
613 }
614
615 switch (retval = sm_bulk (d -> d_name)) {
616 default:
617 if (rp_isbad (retval))
618 adios (NULLCP, "problem delivering msg %s: %s",
619 d -> d_name, rp_string (retval));
620 /* else fall... */
621 case RP_OK:
622 case RP_NO:
623 case RP_NDEL:
624 advise (NULLCP, "msg %s: %s", d -> d_name, rp_string (retval));
625 break;
626 }
627 }
628
629 if (sm == OK) {
630 register int j;
631 int l,
632 m;
633 struct direct **newlist;
634
635 while ((l = scandir (".", &newlist, dselect, dcompar)) > OK) {
636 m = 0;
637
638 for (j = 0; j < l; j++) {
639 register struct direct *d = newlist[j];
640
641 for (i = 0; i < n; i++)
642 if (strcmp (d -> d_name, namelist[i] -> d_name) == 0)
643 break;
644 if (i >= n) {
645 switch (retval = sm_bulk (d -> d_name)) {
646 default:
647 if (rp_isbad (retval))
648 adios (NULLCP, "problem delivering msg %s: %s",
649 d -> d_name, rp_string (retval));
650 /* else fall... */
651 case RP_OK:
652 case RP_NO:
653 case RP_NDEL:
654 advise (NULLCP, "msg %s: %s", d -> d_name,
655 rp_string (retval));
656 break;
657 }
658
659 m = 1;
660 }
661 }
662
663 for (i = 0; i < n; i++)
664 free ((char *) namelist[i]);
665 free ((char *) namelist);
666 namelist = newlist, n = l;
667
668 if (!m)
669 break;
670 newlist = NULL;
671 }
672 }
673
674 if (sm == OK && rp_isbad (retval = sm_end (OK)))
675 adios (NULLCP, "problem finalizing server: %s", rp_string (retval));
676
677 for (i = 0; i < n; i++)
678 free ((char *) namelist[i]);
679 free ((char *) namelist);
680
681 free ((char *) namelist);
682
683 done (0);
684 }
685 #endif