home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume25 / fromwho / fromwho.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-12  |  6.9 KB  |  313 lines

  1. /*
  2.   fromwho -- 'from' with extras
  3.  
  4.   This is a new 'from' program.  Instead of just listing who your mail is
  5.   from, it tells you how many total messages, how many are new, and
  6.   for each person you have mail from, tells how many messages they sent,
  7.   how many are new, and lists the subjects of the messages.
  8.  
  9.   This code is public domain.  I might keep updating it, or I might forget
  10.   about it ]:)  But feel free to mail comments / suggestions to me at
  11.     jearls@data.acs.calpoly.edu
  12.  
  13.   Usage:
  14.     fromwho [-l] [-s] [-n] [-f [<mailbox>]]
  15.  
  16.     -l  Turns listing of users/subjects off.
  17.     -s  Turns listing of subjects off.
  18.     -f  Sets the mailbox to read from.
  19.     -n  List only new mail
  20.  
  21.   REVISION INFORMATION
  22.  
  23.   $Revision: 1.3 $
  24.  
  25.     $Author: jearls $
  26.       $Date: 91/12/03 11:14:33 $
  27.  
  28.   Modification Log:
  29.  
  30.   $Log:    fromwho.c,v $
  31.     Revision 1.3  91/12/03  11:14:33  jearls
  32.     PATCH3: Added `-v' option to display the version number.
  33.     
  34.     Revision 1.2  91/11/23  12:49:37  jearls
  35.     PATCH2: Fixed miscellanous bugs, added '-n' option to
  36.     PATCH2: list only new mail.
  37.     
  38.     Revision 1.1  91/10/19  17:05:17  jearls
  39.     PATCH1: Added support for AIX and other systems that don't
  40.     PATCH1: use a mail spool.
  41.     
  42.     Revision 1.0  91/10/19  14:40:24  jearls
  43.     Initial revision
  44.     
  45. */
  46.  
  47. #include <stdio.h>
  48. #include <pwd.h>
  49. #include <utmp.h>
  50. #include <strings.h>
  51.  
  52. #include "patchlevel.h"
  53.  
  54. #ifndef MAILDIR
  55. #define MAILDIR "/usr/spool/mail/"
  56. #endif  MAILDIR
  57.  
  58. typedef struct {
  59.   int msgs; int new;
  60. } mailinfo;
  61.  
  62. typedef struct subjnode {
  63.   char *subj;
  64.   int new;
  65.   struct subjnode *next;
  66. } subjnode;
  67.  
  68. typedef struct userinfo {
  69.   char *name;
  70.   mailinfo info;
  71.  
  72.   subjnode *subjs, *lastsub;
  73.  
  74.   struct userinfo *next;
  75. } userinfo;
  76.  
  77. char *strdup(char *p)
  78. {
  79.   char *s = (char *)malloc(1+strlen(p));
  80.   if (s)
  81.     (void)strcpy(s, p);
  82.   return(s);
  83. }
  84.  
  85. char *strdup2(char *p, char *q)
  86. {
  87.   char *s = (char *)malloc(1+strlen(p)+strlen(q));
  88.   if (s)
  89.     (void)strcat(strcpy(s, p), q);
  90.   return(s);
  91. }
  92.  
  93. /* translate MAILFILE into a real path */
  94. char *translate(char *mf, char *n, char *h)
  95. {
  96.   int len;
  97.   char *s, *p, *q;
  98.  
  99.   len = strlen(mf);
  100.   if (*mf == '~')
  101.     len += strlen(h) - 1;
  102.   p = mf;
  103.   while (p = index(p, '*')) {
  104.     p++;
  105.     len += strlen(n)-1;
  106.   }
  107.   if (s = (char *)malloc(len+1)) {
  108.     p = s;
  109.     if (*mf == '~') {
  110.       while (*h)
  111.     *(p++) = *(h++);
  112.       mf++;
  113.     } else
  114.       p = s;
  115.     while (*mf)
  116.       if ((*p = *(mf++)) == '*') {
  117.     q = n;
  118.     while (*q)
  119.       *(p++) = *(q++);
  120.       } else
  121.         p++;
  122.     *p = '\0';
  123.   }
  124.   return(s);
  125. }
  126.  
  127. mailinfo mailstats(FILE *f, userinfo **ui)
  128. {
  129.   mailinfo *mp, mi;
  130.   char buf[1024];
  131.   int stat, lp;
  132.   userinfo *p, *b, *n;
  133.  
  134.   mi.msgs = mi.new = 0;
  135.  
  136.   stat = 0;
  137.   while (fgets(buf, 1024, f)) {
  138.     if ((!stat) && (!strncmp(buf, "From ", 5))) {
  139.       for (lp=0; buf[lp+5] != ' '; lp++)
  140.         buf[lp] = buf[lp+5];
  141.       buf[lp] = '\0';
  142.       stat = 1;
  143.       mi.msgs++;
  144.       p = *ui; b = (userinfo *)NULL;
  145.       while (p && (strcmp(buf, p->name) > 0))
  146.         p = (b=p)->next;
  147.       if (!p || (strcmp(buf, p->name))) {
  148.         n = (userinfo *)malloc(sizeof(userinfo));
  149.         n->name = strdup(buf);
  150.         n->info.msgs = n->info.new = 0;
  151.         n->subjs = n->lastsub = (subjnode *)NULL;
  152.         n->next = p;
  153.         if (b)
  154.           b->next = n;
  155.         else
  156.           *ui = n;
  157.         p = n;
  158.       }
  159.       mp = &(p->info);
  160.       mp->msgs++;
  161.       if (p->lastsub)
  162.         p->lastsub = (p->lastsub->next = (subjnode *)malloc(sizeof(subjnode)));
  163.       else
  164.         p->subjs = p->lastsub = (subjnode *)malloc(sizeof(subjnode));
  165.       p->lastsub->subj = (char *)NULL;
  166.       p->lastsub->new = 0;
  167.       p->lastsub->next = (subjnode *)NULL;
  168.     }
  169.     if ((stat) && (!strncmp(buf, "Subject:", 8)))
  170.       if (!p->lastsub->subj) {
  171.         buf[strlen(buf)-1] = '\0';
  172.         p->lastsub->subj = strdup(buf+9);
  173.       }
  174.     if ((stat) && (!strncmp(buf, "Status:", 7))) {
  175.       stat++;
  176.     }
  177.     if ((stat) && (*buf == '\n')) {
  178.       if (stat == 1) {
  179.         mi.new++;
  180.         mp->new++;
  181.         p->lastsub->new = 1;
  182.       }
  183.       stat = 0;
  184.     }
  185.   }
  186.  
  187.   return(mi);
  188. }
  189.  
  190. void usage(char *name)
  191. {
  192.   fprintf(stderr, "usage: %s [-l] [-s] [-n] [-f [<filename>]]\n", name);
  193.   exit(-1);
  194. }
  195.  
  196. int main(int argc, char **argv)
  197. {
  198.   mailinfo mi;
  199.   userinfo *ui = (userinfo *)NULL, *p;
  200.   char *mbox, *prog, myname[9], *home;
  201.   extern char *getenv(char *);
  202.   int flag, listflag = 1, subjflag = 1, newflag = 0;
  203.   int lp;
  204.   FILE *f;
  205.   subjnode *sp, *tp;
  206.  
  207.   extern int errno;
  208.  
  209. /* get user name and home directory */
  210.   f=(FILE *)fopen("/etc/utmp", "r");
  211.   if (f==(FILE *)NULL) {
  212.     perror("Can't open /etc/utmp");
  213.     exit(1);
  214.   }
  215.   fseek(f, 8+sizeof(struct utmp)*ttyslot(), 0);
  216.   myname[8]='\0';
  217.   if (fread(myname, 8, 1, f) < 8) {
  218.     if (!(home = getenv("USER")))
  219.       if (!(home = getenv("USERNAME")))
  220.         if (!(home = getenv("LOGNAME"))) {
  221.           fprintf(stderr, "%s: Who are you?\n", *argv);
  222.           exit(1);
  223.         }
  224.     (void)strcpy(myname, home);
  225.   }
  226.   fclose(f);
  227.  
  228.   if (getpwnam(myname))
  229.     home = strdup(getpwnam(myname)->pw_dir);
  230.   else
  231.     fprintf(stderr, "%s: Who are you?\n", *argv);
  232.  
  233. #ifdef MAILFILE
  234.   mbox = translate(MAILFILE, myname, home);
  235. #else
  236.   mbox = strdup2(MAILDIR, myname);
  237. #endif
  238.  
  239. /* parse arguments */
  240.   prog = *argv;
  241.   while ((--argc) && (**(++argv) == '-')) {
  242.     switch(*(*argv+1)) {
  243.       case 'f' :  (void)free(mbox);
  244.                   if (--argc)
  245.                     mbox = strdup(*(++argv));
  246.                   else {
  247.                    mbox = strdup2(home, "/mbox");
  248.                    argc++;
  249.                   }
  250.                   break;
  251.       case 's' :  subjflag = 0;
  252.                   break;
  253.       case 'l' :  listflag = 0;
  254.                   break;
  255.       case 'n' :  newflag = 1;
  256.           break;
  257.       case 'v' :  puts("fromwho, by johnson earls.  $Revision: 1.3 $");
  258.           exit(0);
  259.       default :   free(home);
  260.                   free(mbox);
  261.                   usage(prog);
  262.     }
  263.   }
  264.  
  265. /* open the file */
  266.   f = (FILE *)fopen(mbox, "r");
  267.   if (f == (FILE *)NULL) {
  268.     perror(mbox);
  269.     free(home);
  270.     free(mbox);
  271.     exit(errno);
  272.   }
  273.  
  274. /* get the info */
  275.   mi = mailstats(f, &ui);
  276.  
  277.   (void)fclose(f);
  278.  
  279. /* print everything out */
  280.   if (newflag)
  281.     printf("%s contains %d new messages.\n", mbox, mi.new);
  282.   else
  283.     printf("%s contains %d messages, %d new.\n", mbox, mi.msgs, mi.new);
  284.   while (ui) {
  285.     if (listflag && (!newflag || ui->info.new))
  286.       if (newflag)
  287.         printf("  %-36s:  %d new messages.\n", ui->name, ui->info.new);
  288.       else
  289.         printf("  %-36s:  %d messages, %d new.\n", ui->name, ui->info.msgs, ui->info.new);
  290.     for (sp = ui->subjs; sp; ) {
  291.       if (sp->subj) {
  292.         if (listflag && subjflag)
  293.       if (sp->new || !newflag)
  294.             printf("    %c %s\n", (sp->new ? '>' : ' '), sp->subj);
  295.         free(sp->subj);
  296.       } else
  297.         if (listflag && subjflag)
  298.       if (sp->new || !newflag)
  299.             printf("    %c <none>\n", (sp->new ? '>' : ' '));
  300.       sp = (tp=sp) -> next;
  301.       free(tp);
  302.     }
  303.     ui = (p=ui)->next;
  304.     free(p->name);
  305.     free(p);
  306.   }
  307.  
  308.   free(home);
  309.   free(mbox);
  310.  
  311.   exit(0);
  312. }
  313.