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