source: trunk/third/nmh/uip/popi.c @ 12455

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