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

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