]> diplodocus.org Git - nmh/blob - uip/popi.c
Cope with sasl_decode64() returning SASL_CONTINUE as well as SASL_OK.
[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 <h/utils.h>
17 #include <errno.h>
18
19 #ifndef RPOP
20 # define RPOPminc(a) (a)
21 #else
22 # define RPOPminc(a) 0
23 #endif
24
25 #ifndef APOP
26 # define APOPminc(a) (a)
27 #else
28 # define APOPminc(a) 0
29 #endif
30
31 #ifndef BPOP
32 # define BPOPminc(a) (a)
33 #else
34 # define BPOPminc(a) 0
35 #endif
36
37 #ifndef SMTPMTS
38 # define BULKminc(a) (a)
39 #else
40 # define BULKminc(a) 0
41 #endif
42
43 static struct swit switches[] = {
44 #define APOPSW 0
45 { "apop", APOPminc (-4) },
46 #define NAPOPSW 1
47 { "noapop", APOPminc (-6) },
48 #define AUTOSW 2
49 { "auto", BPOPminc(-4) },
50 #define NAUTOSW 3
51 { "noauto", BPOPminc(-6) },
52 #define BULKSW 4
53 { "bulk directory", BULKminc(-4) },
54 #define FORMSW 5
55 { "form formatfile", 0 },
56 #define FMTSW 6
57 { "format string", 5 },
58 #define HOSTSW 7
59 { "host host", 0 },
60 #define PROGSW 8
61 { "mshproc program", 0 },
62 #define RPOPSW 9
63 { "rpop", RPOPminc (-4) },
64 #define NRPOPSW 10
65 { "norpop", RPOPminc (-6) },
66 #define USERSW 11
67 { "user user", 0 },
68 #define WIDTHSW 12
69 { "width columns", 0 },
70 #define VERSIONSW 13
71 { "version", 0 },
72 #define HELPSW 14
73 { "help", 0 },
74 { NULL, 0 }
75 };
76
77 static char *bulksw = NULL;
78 static int snoop = 0;
79 static int width = 0;
80 static char mailname[BUFSIZ];
81 static char *nfs = NULL;
82 static struct msgs *mp;
83
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 = pluspath (cp);
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, NULL, 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 create_folder(maildir, 0, done);
233
234 if (chdir (maildir) == NOTOK)
235 adios (maildir, "unable to change directory to");
236
237 if (!(mp = folder_read (folder)))
238 adios (NULL, "unable to read folder %s", folder);
239
240 #ifdef BPOP
241 if (autosw)
242 msh ();
243 else
244 #endif
245
246 popi();
247 pop_quit();
248
249 context_replace (pfolder, folder); /* update current folder */
250 seq_setunseen (mp, 0); /* set the Unseen-Sequence */
251 seq_save (mp);
252 context_save (); /* save the context file */
253 return done (0);
254 }
255
256
257 static struct swit popicmds[] = {
258 #define DELECMD 0
259 "dele", 0,
260 #define LASTCMD 1
261 "last", 0,
262 #define LISTCMD 2
263 "list", 0,
264 #define NOOPCMD 3
265 "noop", 0,
266 #define QUITCMD 4
267 "quit", 0,
268 #define RETRCMD 5
269 "retr", 0,
270 #define RSETCMD 6
271 "rset", 0,
272 #define SCANCMD 7
273 "scan", 0,
274 #define STATCMD 8
275 "stat", 0,
276 #define TOPCMD 9
277 "top", 0,
278 #ifdef BPOP
279 #define MSHCMD 10
280 "msh", 0,
281 #endif
282
283 NULL, 0
284 };
285
286
287 static void
288 popi (void)
289 {
290 int eof = 0;
291
292 for (;;) {
293 int i;
294 register char *cp;
295 char buffer[BUFSIZ];
296
297 if (eof)
298 return;
299
300 printf ("(%s) ", invo_name);
301 for (cp = buffer; (i = getchar ()) != '\n'; ) {
302 if (i == EOF) {
303 putchar ('\n');
304 if (cp == buffer)
305 return;
306 eof = 1;
307 break;
308 }
309
310 if (cp < buffer + sizeof buffer - 2)
311 *cp++ = i;
312 }
313 *cp = '\0';
314 if (buffer[0] == '\0')
315 continue;
316 if (buffer[0] == '?') {
317 printf ("commands:\n");
318 print_sw (ALL, popicmds, "");
319 printf ("type CTRL-D or use \"quit\" to leave %s\n", invo_name);
320 continue;
321 }
322
323 if (cp = strchr (buffer, ' '))
324 *cp = '\0';
325 switch (i = smatch (buffer, popicmds)) {
326 case AMBIGSW:
327 ambigsw (buffer, popicmds);
328 continue;
329 case UNKWNSW:
330 printf ("%s unknown -- type \"?\" for help\n", buffer);
331 continue;
332
333 case QUITCMD:
334 return;
335
336 case STATCMD:
337 case DELECMD:
338 case NOOPCMD:
339 case LASTCMD:
340 case RSETCMD:
341 case TOPCMD:
342 if (cp)
343 *cp = ' ';
344 pop_command ("%s%s", popicmds[i].sw, cp ? cp : "");
345 printf ("%s\n", response);
346 break;
347
348 case LISTCMD:
349 if (cp)
350 *cp = ' ';
351 if (pop_command ("%s%s", popicmds[i].sw, cp ? cp : "")
352 == OK) {
353 printf ("%s\n", response);
354 if (!cp)
355 for (;;) {
356 switch (pop_multiline ()) {
357 case DONE:
358 strcpy (response, ".");
359 /* and fall... */
360 case NOTOK:
361 printf ("%s\n", response);
362 break;
363
364 case OK:
365 printf ("%s\n", response);
366 continue;
367 }
368 break;
369 }
370 }
371 break;
372
373 case RETRCMD:
374 if (!cp) {
375 advise (NULL, "missing argument to %s", buffer);
376 break;
377 }
378 retr_action (NULL, OK);
379 pop_retr (atoi (++cp), retr_action);
380 retr_action (NULL, DONE);
381 printf ("%s\n", response);
382 break;
383
384 case SCANCMD:
385 {
386 char *dp,
387 *ep,
388 *fp;
389
390 if (width == 0)
391 width = sc_width ();
392
393 for (dp = nfs, i = 0; *dp; dp++, i++)
394 if (*dp == '\\' || *dp == '"' || *dp == '\n')
395 i++;
396 i++;
397 ep = mh_xmalloc ((unsigned) i);
398 for (dp = nfs, fp = ep; *dp; dp++) {
399 if (*dp == '\n') {
400 *fp++ = '\\', *fp++ = 'n';
401 continue;
402 }
403 if (*dp == '"' || *dp == '\\')
404 *fp++ = '\\';
405 *fp++ = *dp;
406 }
407 *fp = '\0';
408
409 pop_command ("xtnd scan %d \"%s\"", width, ep);
410 printf ("%s\n", response);
411
412 free (ep);
413 }
414 break;
415
416 #ifdef BPOP
417 case MSHCMD:
418 msh ();
419 break;
420 #endif
421 }
422 }
423 }
424
425
426 static int
427 retr_action (char *rsp, int flag)
428 {
429 static FILE *fp;
430
431 if (rsp == NULL) {
432 static int msgnum;
433 static char *cp;
434
435 if (flag == OK) {
436 if (!(mp = folder_realloc (mp, mp->lowoff, msgnum = mp->hghmsg + 1)))
437 adios (NULL, "unable to allocate folder storage");
438
439 cp = getcpy (m_name (mp->hghmsg + 1));
440 if ((fp = fopen (cp, "w+")) == NULL)
441 adios (cp, "unable to write");
442 chmod (cp, m_gmprot ());
443 }
444 else {
445 struct stat st;
446
447 fflush (fp);
448 if (fstat (fileno (fp), &st) != NOTOK && st.st_size > 0) {
449 clear_msg_flags (mp, msgnum);
450 set_exists (mp, msgnum);
451 set_unseen (mp, msgnum);
452 mp->msgflags |= SEQMOD;
453
454 if (ferror (fp))
455 advise (cp, "write error on");
456 mp->hghmsg = msgnum;
457 }
458 else
459 unlink (cp);
460
461 fclose (fp), fp = NULL;
462 free (cp), cp = NULL;
463 }
464
465 return;
466 }
467
468 fprintf (fp, "%s\n", rsp);
469 }
470
471
472 #ifdef BPOP
473 static void
474 msh (void)
475 {
476 int child_id, vecp;
477 char buf1[BUFSIZ], buf2[BUFSIZ], *vec[9];
478
479 if (pop_fd (buf1, sizeof(buf1), buf2, sizeof(buf2)) == NOTOK)
480 adios (NULL, "%s", response);
481
482 vecp = 0;
483 vec[vecp++] = r1bindex (mshproc, '/');
484
485 switch (child_id = fork ()) {
486 case NOTOK:
487 adios ("fork", "unable to");
488
489 case OK:
490 vec[vecp++] = "-popread";
491 vec[vecp++] = buf1;
492 vec[vecp++] = "-popwrite";
493 vec[vecp++] = buf2;
494 vec[vecp++] = "-idname";
495 vec[vecp++] = mailname;
496 vec[vecp++] = mailname;
497 vec[vecp] = NULL;
498 execvp (mshproc, vec);
499 fprintf (stderr, "unable to exec ");
500 perror (mshproc);
501 _exit (-1);
502
503 default:
504 pidXwait (child_id, mshproc);
505 break;
506 }
507 }
508 #endif
509
510
511 #ifdef SMTPMTS
512 #include <h/mts.h>
513 #include <mts/smtp/smtp.h>
514
515 static int
516 dselect (struct direct *d)
517 {
518 int i;
519
520 if ((i = strlen (d->d_name)) < sizeof "smtp"
521 || strncmp (d->d_name, "smtp", sizeof "smtp" - 1))
522 return 0;
523 return ((i -= (sizeof ".bulk" - 1)) > 0
524 && !strcmp (d->d_name + i, ".bulk"));
525 }
526
527
528 static int
529 dcompar (struct direct *d1, struct direct *d2)
530 {
531 struct stat s1, s2;
532
533 if (stat ((*d1)->d_name, &s1) == NOTOK)
534 return 1;
535 if (stat ((*d2)->d_name, &s2) == NOTOK)
536 return -1;
537 return ((int) (s1.st_mtime - s2.st_mtime));
538 }
539
540
541 static void
542 do_bulk (char *host)
543 {
544 register int i;
545 int n, retval, sm;
546 struct direct **namelist;
547
548 if (chdir (bulksw) == NOTOK)
549 adios (bulksw, "unable to change directory to");
550
551 if ((n = scandir (".", &namelist, dselect, dcompar)) == NOTOK)
552 adios (bulksw, "unable to scan directory");
553
554 sm = NOTOK;
555 for (i = 0; i < n; i++) {
556 register struct direct *d = namelist[i];
557
558 if (sm == NOTOK) {
559 if (rp_isbad (retval = sm_init (NULL, host, 1, 1, snoop)))
560 adios (NULL, "problem initializing server: %s",
561 rp_string (retval));
562 else
563 sm = OK;
564 }
565
566 switch (retval = sm_bulk (d->d_name)) {
567 default:
568 if (rp_isbad (retval))
569 adios (NULL, "problem delivering msg %s: %s",
570 d->d_name, rp_string (retval));
571 /* else fall... */
572 case RP_OK:
573 case RP_NO:
574 case RP_NDEL:
575 advise (NULL, "msg %s: %s", d->d_name, rp_string (retval));
576 break;
577 }
578 }
579
580 if (sm == OK) {
581 register int j;
582 int l,
583 m;
584 struct direct **newlist;
585
586 while ((l = scandir (".", &newlist, dselect, dcompar)) > OK) {
587 m = 0;
588
589 for (j = 0; j < l; j++) {
590 register struct direct *d = newlist[j];
591
592 for (i = 0; i < n; i++)
593 if (strcmp (d->d_name, namelist[i]->d_name) == 0)
594 break;
595 if (i >= n) {
596 switch (retval = sm_bulk (d->d_name)) {
597 default:
598 if (rp_isbad (retval))
599 adios (NULL, "problem delivering msg %s: %s",
600 d->d_name, rp_string (retval));
601 /* else fall... */
602 case RP_OK:
603 case RP_NO:
604 case RP_NDEL:
605 advise (NULL, "msg %s: %s", d->d_name,
606 rp_string (retval));
607 break;
608 }
609
610 m = 1;
611 }
612 }
613
614 for (i = 0; i < n; i++)
615 free ((char *) namelist[i]);
616 free ((char *) namelist);
617 namelist = newlist, n = l;
618
619 if (!m)
620 break;
621 newlist = NULL;
622 }
623 }
624
625 if (sm == OK && rp_isbad (retval = sm_end (OK)))
626 adios (NULL, "problem finalizing server: %s", rp_string (retval));
627
628 for (i = 0; i < n; i++)
629 free ((char *) namelist[i]);
630 free ((char *) namelist);
631
632 free ((char *) namelist);
633
634 done (0);
635 }
636 #endif