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

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