source: trunk/athena/bin/from/from.c @ 12350

Revision 12350, 12.7 KB checked in by ghudson, 26 years ago (diff)
Some RCS ID cleanup: delete $Log$ and replace other RCS keywords with $Id$.
Line 
1/*
2 * $Id: from.c,v 1.23 1999-01-22 23:10:24 ghudson Exp $
3 *
4 * This is the main source file for a KPOP version of the from command.
5 * It was written by Theodore Y. Ts'o, MIT Project Athena.  And later
6 * modified by Jerry Larivee, MIT Project Athena,  to support both KPOP
7 * and the old UCB from functionality.
8 */
9
10#if !defined(lint) && !defined(SABER)
11static char *rcsid = "$Id: from.c,v 1.23 1999-01-22 23:10:24 ghudson Exp $";
12#endif /* lint || SABER */
13
14#include <stdio.h>
15#include <sys/ioctl.h>
16#include <sys/types.h>
17#include <pwd.h>
18#include <string.h>
19#include <stdlib.h>
20#include <ctype.h>
21#include <sys/stat.h>
22#include <termios.h>
23#ifdef HAVE_HESIOD
24#include <hesiod.h>
25#endif
26#define NOTOK (-1)
27#define OK 0
28#define DONE 1
29
30#define MAX_HEADER_LINES 512
31
32#ifdef OFF_SWITCH
33/*
34 * if the ok file does not exist, then print the default error and do not
35 * proceed with the request. If the ok file is missing and the message
36 * file exists, print the contents of the message file and do not proceed
37 * with the request. The message file will be ignored if the ok file exists.
38 */
39
40#define OK_FILE   "/afs/athena.mit.edu/system/config/from/ok"
41#define MSG_FILE  "/afs/athena.mit.edu/system/config/from/message"
42char    *default_err = "Cannot stat the \"ok\" file.. unable to continue with request.";
43#endif /* OFF_SWITCH */
44
45FILE    *sfi, *sfo;
46char    Errmsg[80];
47char    *getlogin(), *parse_from_field();
48extern int      optind;
49extern char     *optarg;
50struct  passwd *getpwuid();
51uid_t   getuid();
52
53int     popmail_debug, verbose, unixmail, popmail, report, totals;
54int     exuser, nonomail;
55char    *progname, *sender, *user, *host;
56
57char    *headers[MAX_HEADER_LINES];
58int     num_headers, skip_message;
59
60char *Short_List[] = {
61        "from", NULL
62        };
63
64char *Report_List[] = {
65        "from", "subject", NULL
66        };
67
68char *Verbose_List[] = {
69        "to", "from", "subject", "date", NULL
70        };
71
72       
73main(argc, argv)
74        int     argc;
75        char    **argv;
76{
77        int     locmail = -1, remmail = -1;
78
79        parse_args(argc,argv);
80        if (unixmail)
81          locmail = getmail_unix(user);
82        if (popmail)
83          remmail = getmail_pop(user, host, locmail);
84        if (!nonomail && (report || verbose || totals) &&
85            (unixmail == 0 || locmail == 0) &&
86            (popmail == 0 || remmail == 0))
87          if (exuser)
88            printf ("%s doesn't have any mail waiting.\n", user);
89          else
90            puts("You don't have any mail waiting.");
91
92        exit (unixmail && locmail < 0 || popmail && remmail < 0);
93}
94
95parse_args(argc,argv)
96        int     argc;
97        register char **argv;
98{
99        register struct passwd *pp;
100        char *cp;
101        int     c;
102        extern char     *getenv();
103#ifdef HAVE_HESIOD
104        struct hes_postoffice *p;
105#endif
106
107        cp = strrchr(argv[0], '/');
108        if (cp)
109            progname = cp + 1;
110        else
111            progname = argv[0];
112        verbose = popmail_debug = 0;
113        host = user = sender = NULL;
114        unixmail = popmail = 1;
115       
116        optind = 1;
117        while ((c = getopt(argc,argv,"rvdnputs:h:")) != EOF)
118                switch(c) {
119                case 'r':
120                        /* report on no mail */
121                        report = 1;
122                        break;
123                case 'n':
124                        nonomail = 1;
125                        break;
126                case 'v':
127                        /* verbose mode */
128                        verbose++;
129                        report = 0;
130                        break;
131                case 'd':
132                        /* debug mode */
133                        popmail_debug++;
134                        break;
135                case 'p':
136                        /* check pop only */
137                        unixmail = 0;
138                        break;
139                case 'u':
140                        /* check unix mail only */
141                        popmail = 0;
142                        break;
143                case 's':
144                        /* check for mail from sender only */
145                        sender = optarg;
146                        break;
147                case 'h':
148                        /* specify pobox host */
149                        host = optarg;
150                        break;
151                case 't':
152                        /* print total messages only */
153                        totals = 1;
154                        report = 0;
155                        verbose = 0;
156                        break;
157                case '?':
158                        lusage();
159                }
160        /* check mail for user */
161        if (optind < argc) {
162                exuser = 1;
163                user = argv[optind];
164        } else {
165                user = getenv ("USER");
166                if (user == NULL)
167                        user = strdup(getlogin());
168                if (!user || !*user) {
169                        pp = getpwuid((int) getuid());
170                        if (pp == NULL) {
171                                fprintf (stderr, "%s: user not in password file\n", progname);
172                                exit(1);
173                        }
174                        user = pp->pw_name;
175                }
176              }
177       
178        if (popmail) {
179          if (!host)
180            host = getenv("MAILHOST");
181#ifdef HAVE_HESIOD
182          if (!host) {
183            p = hes_getmailhost(user);
184            if (p && !strcmp(p->po_type, "POP"))
185              host = p->po_host;
186          }
187#endif
188          if (!host) {
189            if (exuser)
190              fprintf(stderr, "%s: can't find post office server for user %s.\n",
191                      progname, user);
192            else
193              fprintf(stderr, "%s: can't find post office server.\n", progname);
194
195            if (!unixmail) {
196              return(1);
197            }
198            fprintf(stderr, "%s: Trying unix mail drop...\n", progname);
199            popmail = 0;
200          }
201        }
202        return 0;
203}
204
205lusage()
206{
207        fprintf(stderr, "Usage: %s [-v | -r | -t] [-p | -u] [-s sender] [-h host] [user]\n", progname);
208        exit(1);
209}
210
211
212getmail_pop(user, host, printhdr)
213     char       *user,*host;
214     int        printhdr;
215{
216        int nmsgs, nbytes, linelength;
217        char response[128];
218        register int i, j;
219        struct winsize windowsize;
220        int     header_scan();
221
222#ifdef OFF_SWITCH
223        if(pop_ok() == NOTOK)
224             return (1);
225#endif /* OFF_SWITCH */
226
227        if (pop_init(host) == NOTOK) {
228                error(Errmsg);
229                return(1);
230        }
231
232        if ((getline(response, sizeof response, sfi) != OK) ||
233            (*response != '+')){
234                error(response);
235                return -1;
236        }
237
238#ifdef HAVE_KRB4
239        if (pop_command("USER %s", user) == NOTOK ||
240            pop_command("PASS %s", user) == NOTOK)
241#else
242        if (pop_command("USER %s", user) == NOTOK ||
243            pop_command("RPOP %s", user) == NOTOK)
244#endif
245        {
246                error(Errmsg);
247                (void) pop_command("QUIT");
248                return -1;
249        }
250
251        if (pop_stat(&nmsgs, &nbytes) == NOTOK) {
252                error(Errmsg);
253                (void) pop_command("QUIT");
254                return -1;
255        }
256        if (nmsgs == 0) {
257                (void) pop_command("QUIT");
258                return(0);
259        }
260        if (verbose || totals)
261                printf("You have %d %s (%d bytes) on %s%c\n",
262                       nmsgs, nmsgs > 1 ? "messages" : "message",
263                       nbytes, host, verbose ? ':' : '.');
264        if (totals) {
265                (void) pop_command("QUIT");
266                return nmsgs;
267        }
268        if (printhdr)
269                puts("POP mail:");
270
271        /* find out how long the line is for the stdout */
272        if ((ioctl(1, TIOCGWINSZ, (void *)&windowsize) < 0) ||
273            (windowsize.ws_col == 0))
274                windowsize.ws_col = 80;         /* default assume 80 */
275        /* for the console window timestamp */
276        linelength = windowsize.ws_col - 6;
277        if (linelength < 32)
278                linelength = 32;
279       
280        for (i = 1; i <= nmsgs; i++) {
281                if (verbose && !skip_message)
282                        putchar('\n');
283                num_headers = skip_message = 0;
284                if (pop_scan(i, header_scan) == NOTOK) {
285                        error(Errmsg);
286                        (void) pop_command("QUIT");
287                        return -1;
288                }
289                if (report) {
290                        if (!skip_message)
291                                print_report(headers, num_headers, linelength);
292                        else
293                                for (j=0; j<num_headers; j++)
294                                        free(headers[j]);
295                } else {
296                        for (j=0; j<num_headers; j++) {
297                                if (!skip_message)
298                                        puts(headers[j]);
299                                free(headers[j]);
300                        }
301                }
302        }
303       
304        (void) pop_command("QUIT");
305        return nmsgs;
306}
307
308header_scan(line, last_header)
309        char    *line;
310        int     *last_header;
311{
312        char    *keyword, **search_list;
313        register int    i;
314       
315        if (*last_header && isspace(*line)) {
316                headers[num_headers++] = strdup(line);
317                return;
318        }
319
320        for (i=0;line[i] && line[i]!=':';i++) ;
321        keyword=malloc((unsigned) i+1);
322        if (keyword == NULL)
323          {
324            fprintf (stderr, "%s: out of memory\n", progname);
325            exit (1);
326          }
327        (void) strncpy(keyword,line,i);
328        keyword[i]='\0';
329        MakeLowerCase(keyword);
330        if (sender && !strcmp(keyword,"from")) {
331                char *mail_from = parse_from_field(line+i+1);
332                if (strcmp(sender, mail_from))
333                        skip_message++;
334                free (mail_from);
335              }
336        if (verbose)
337          search_list = Verbose_List;
338        else if (report)
339          search_list = Report_List;
340        else
341          search_list = Short_List;
342        if (list_compare(keyword, search_list)) {
343                *last_header = 1;
344                headers[num_headers++] = strdup(line);
345        } else
346                *last_header = 0;       
347}
348
349pop_scan(msgno,action)
350        int     msgno;
351        int     (*action)();
352{       
353        char buf[4096];
354        int     headers = 1;
355        int     scratch = 0;    /* Scratch for action() */
356
357        (void) sprintf(buf, "RETR %d", msgno);
358        if (popmail_debug) fprintf(stderr, "%s\n", buf);
359        if (putline(buf, Errmsg, sfo) == NOTOK)
360                return(NOTOK);
361        if (getline(buf, sizeof buf, sfi) != OK) {
362                (void) strcpy(Errmsg, buf);
363                return(NOTOK);
364        }
365        while (headers) {
366                switch (multiline(buf, sizeof buf, sfi)) {
367                case OK:
368                        if (!*buf)
369                                headers = 0;
370                        (*action)(buf,&scratch);
371                        break;
372                case DONE:
373                        return(OK);
374                case NOTOK:
375                        return(NOTOK);
376                }
377        }
378        while (1) {
379                switch (multiline(buf, sizeof buf, sfi)) {
380                case OK:
381                        break;
382                case DONE:
383                        return(OK);
384                case NOTOK:
385                        return(NOTOK);
386                }
387        }
388}
389
390/* Print error message.  `s1' is printf control string, `s2' is arg for it. */
391
392/*VARARGS1*/
393error (s1, s2)
394     char *s1, *s2;
395{
396  fprintf (stderr, "pop: ");
397  fprintf (stderr, s1, s2);
398  putc ('\n', stderr);
399}
400
401int list_compare(s,list)
402      char *s,**list;
403{
404      char *retval;
405
406      while (*list!=NULL) {
407              if (strcmp(*list++, s) == 0)
408                      return(1);
409      }
410      return(0);
411}
412
413MakeLowerCase(s)
414      char *s;
415{
416      int i;
417      for (i=0;s[i];i++)
418              s[i]=isupper(s[i]) ? tolower(s[i]) : s[i];
419}
420
421char *parse_from_field(str)
422        char    *str;
423{
424        register char   *cp, *scr;
425        char            *stored;
426       
427        stored = scr = strdup(str);
428        while (*scr && isspace(*scr))
429                scr++;
430        if (cp = strchr(scr, '<'))
431                scr = cp+1;
432        if (cp = strchr(scr, '@'))
433                *cp = '\0';
434        if (cp = strchr(scr, '>'))
435                *cp = '\0';
436        scr = strdup(scr);
437        MakeLowerCase(scr);
438        free(stored);
439        return(scr);
440}
441
442/*
443 * Do the old unix mail lookup.
444 */
445
446getmail_unix(user)
447     char *user;
448{
449        char lbuf[BUFSIZ];
450        char lbuf2[BUFSIZ];
451        int havemail = 0, stashed = 0;
452        register char *name;
453        char *getlogin();
454        char *maildrop;
455        char *maildir;
456
457        if (sender != NULL)
458          for (name = sender; *name; name++)
459            if (isupper(*name))
460              *name = tolower(*name);
461
462        maildrop = getenv("MAILDROP");
463        if (maildrop && *maildrop) {
464            if (freopen(maildrop, "r", stdin) == NULL) {
465                if (!popmail)
466                    fprintf(stderr, "Can't open maildrop: %s.\n", maildrop);
467                unixmail = 0;
468                return -1;
469            }
470        } else {
471            maildir = "/var/spool/mail";
472            if (chdir(maildir) < 0) {
473                maildir = "/var/mail";
474                if (chdir(maildir) < 0) {
475                    unixmail = 0;
476                    return -1;
477                }
478            }
479            if (freopen(user, "r", stdin) == NULL) {
480                if (!popmail)
481                    fprintf(stderr, "Can't open %s/%s.\n", maildir, user);
482                unixmail = 0;
483                return -1;
484            }
485        }
486
487        while (fgets(lbuf, sizeof lbuf, stdin) != NULL)
488                if (lbuf[0] == '\n' && stashed) {
489                        stashed = 0;
490                        if (!havemail && !totals && popmail)
491                                puts("Local mail:");
492                        if (!totals)
493                                fputs(lbuf2, stdout);
494                        havemail++;
495                } else if (strncmp(lbuf, "From ", 5) == 0 &&
496                    (sender == NULL || match(&lbuf[4], sender))) {
497                        strcpy(lbuf2, lbuf);
498                        stashed = 1;
499                }
500        if (stashed && !totals)
501                fputs(lbuf2, stdout);
502        if (totals && havemail) {
503                struct stat st;
504                if (fstat(0, &st) != -1)
505                        printf("You have %d local message%s (%d bytes).\n",
506                               havemail, havemail > 1 ? "s" : "",
507                               st.st_size);
508                else
509                        printf("You have %d local message%s.\n",
510                               havemail, havemail > 1 ? "s" : "");
511        }
512        return havemail;
513}
514
515match (line, str)
516        register char *line, *str;
517{
518        register char ch;
519
520        while (*line == ' ' || *line == '\t')
521                ++line;
522        if (*line == '\n')
523                return (0);
524        while (*str && *line != ' ' && *line != '\t' && *line != '\n') {
525                ch = isupper(*line) ? tolower(*line) : *line;
526                if (ch != *str++)
527                        return (0);
528                line++;
529        }
530        return (*str == '\0');
531}
532
533print_report(headers, num_headers, winlength)
534     char **headers;
535     int num_headers, winlength;
536{
537  int j, len;
538  char *p, *from_field = 0, *subject_field = 0, *buf, *buf1;
539 
540  for(j = 0; j < num_headers; j++) {
541    p = strchr(headers[j], ':');
542    if (p == NULL)
543      continue;
544
545    if (strncmp("From", headers[j], 4) == 0) {
546      p++;
547      while (p[0] == ' ')
548        p++;
549      from_field = p;
550      if (subject_field)
551        break;
552    }
553    else if (strncmp("Subject", headers[j], 7) == 0) {
554      p++;
555      while (p[0] == ' ')
556        p++;
557      subject_field = p;
558      if (from_field)
559        break;
560    }
561  }
562
563  buf = malloc(winlength+1);  /* add 1 for the NULL terminator */
564  if (buf == NULL)
565    {
566      fprintf (stderr, "from: out of memory\n");
567      exit (1);
568    }   
569  buf[0] = '\0';
570  buf[winlength] = '\0';
571  if (from_field)
572    strncpy(buf, from_field, winlength);
573  else
574    strncpy(buf, "<<unknown sender>>", winlength);
575  len = strlen(buf);
576  if  (len < 30)
577    len = 30;
578
579  buf1 = malloc(winlength-len+1);  /* add 1 for the NULL terminator */
580  if (buf1 == NULL)
581    {
582      fprintf (stderr, "from: out of memory\n");
583      exit (1);
584    }   
585  buf1[0] = '\0';
586
587  if (winlength - len - 1 < 1)
588    subject_field = NULL;
589
590  if (subject_field)
591    {
592      strncpy(buf1, subject_field, winlength - len - 1);
593      buf1[winlength - len - 1] = 0;
594    }
595 
596  printf("%-30s %s\n", buf, buf1);
597
598  free(buf);
599  free(buf1);
600  for (j = 0; j < num_headers; j++)
601    free(headers[j]);
602}
603
604
605#ifdef OFF_SWITCH
606
607pop_ok()
608{
609  FILE *fp;
610  struct stat sbuf;
611  char buf[BUFSIZ];
612
613  if(stat(OK_FILE, &sbuf) == 0)
614       return(OK);
615
616  if(!(fp = fopen(MSG_FILE, "r")))  {
617       printf("%s\n", default_err);
618       return(NOTOK);
619  }
620
621  memset(buf, 0, sizeof(buf));
622  while(fgets(buf, sizeof(buf), fp))
623      printf("%s", buf);
624  fclose(fp);
625  return(NOTOK);
626}
627
628#endif /* OFF_SWITCH */
629 
Note: See TracBrowser for help on using the repository browser.