home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / com / utils / elm / sources / readmsg.c < prev    next >
C/C++ Source or Header  |  1992-03-28  |  14KB  |  503 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: readmsg.c,v 4.1.1.2 90/06/21 22:40:12 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 4.1.1.2 $   $State: Exp $
  6.  *
  7.  *             Copyright (c) 1986, 1987 Dave Taylor
  8.  *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log:    readmsg.c,v $
  17.  * Revision 4.1.1.2  90/06/21  22:40:12  syd
  18.  * Reduce occurrences of unprotected "From " confusing message count
  19.  * From: Marius Olafsson
  20.  *
  21.  * Revision 4.1.1.1  90/06/21  22:33:51  syd
  22.  * Fix error message in readmsg and clear variable for use
  23.  * From: Hans Buurman
  24.  *
  25.  * Revision 4.1  90/04/28  22:44:52  syd
  26.  * checkin of Elm 2.3 as of Release PL0
  27.  *
  28.  *
  29.  ******************************************************************************/
  30.  
  31. /** This routine adds the functionality of the "~r" command to the Elm mail
  32.     system while still allowing the user to use the editor of their choice.
  33.  
  34.     The program, without any arguments, tries to read a file in the users home
  35.     directory called ".readmsg" (actually defined in the sysdefs.h system
  36.     defines file) and if it finds it reads the current message.  If it doesn't
  37.     find it, it will return a usage error.
  38.  
  39.     The program can also be called with an explicit message number, list of
  40.     message numbers, or a string to match in the message (including the header).
  41.     NOTE that when you use the string matching option it will match the first
  42.     message containing that EXACT (case sensitive) string and then exit.
  43. **/
  44.  
  45. #include <stdio.h>
  46. #include <ctype.h>
  47. #include <pwd.h>
  48.  
  49. #include "defs.h"
  50.  
  51. /** three defines for what level of headers to display **/
  52.  
  53. #define ALL        1
  54. #define WEED        2
  55. #define NONE        3
  56.  
  57. #define metachar(c)    (c == '=' || c == '+' || c == '%')
  58.  
  59. static char ident[] = { WHAT_STRING };
  60.  
  61. #define  MAX_LIST    25        /* largest single list of arguments */
  62.  
  63. #define  LAST_MESSAGE    9999        /* last message in list ('$' char)  */
  64. #define  LAST_CHAR    '$'        /* char to delimit last message..   */
  65. #define  STAR        '*'        /* char to delimit all messages...  */
  66.  
  67. int read_message[MAX_LIST];         /* list of messages to read        */
  68. int messages = 0;            /* index into list of messages      */
  69.  
  70. int numcmp();                /* strcmp, but for numbers          */
  71. char *words();                /* function defined below...        */
  72.  
  73. struct passwd *getpwuid();
  74. struct passwd *pass;
  75. char home[SLEN];        /* the users home directory  */
  76.  
  77. extern char *optarg;        /* for parsing the ...             */
  78. extern int   optind;            /*  .. starting arguments           */
  79.  
  80. char *getenv();                /* keep lint happy */
  81.  
  82. main(argc, argv)
  83. int argc;
  84. char *argv[];
  85. {
  86.     FILE *file;                    /* generic file descriptor! */
  87.     char filename[SLEN],             /* filename buffer          */
  88.          infile[SLEN],            /* input filename        */
  89.          buffer[SLEN],             /* file reading buffer      */
  90.          string[SLEN],            /* string match buffer      */
  91.          *cp,
  92.              *prog = argv[0];
  93.  
  94.     int current_in_queue = 0,         /* these are used for...     */
  95.         current = 0,            /* ...going through msgs     */
  96.         list_all_messages = 0,        /* just list 'em all??       */
  97.         num,                 /* for argument parsing      */
  98.         page_breaks = 0,            /* use "^L" breaks??         */
  99.             total,                /* number of msgs current    */
  100.         include_headers = WEED,         /* flag: include msg header? */
  101.         last_message = 0,             /* flag: read last message?  */
  102.         not_in_header = 0,            /* flag: in msg header?      */
  103. #ifdef MMDF
  104.         newheader = 0,            /* flag: hit ^A^A^A^A line   */
  105. #endif /* MMDF */
  106.         string_match = 0;            /* flag: using string match?  */
  107.         string[0] = '\0';            /* init match string to empty */
  108.         infile[0] = '\0';            /* init mail file to empty    */
  109.  
  110.         initpaths();
  111.  
  112.     /**** start of the actual program ****/
  113.  
  114.     while ((num = getopt(argc, argv, "nhf:p")) != EOF) {
  115.       switch (num) {
  116.         case 'n' : include_headers = NONE;        break;
  117.         case 'h' : include_headers = ALL;        break;
  118.         case 'f' : strcpy(infile, optarg);
  119.                if (metachar(infile[0]))
  120.                      if (expand(infile) == 0)
  121.                        printf("%s: couldn't expand filename %s!\n",
  122.                       argv[0], infile);
  123.                break;
  124.         case 'p' : page_breaks++;            break;
  125.         case '?' : usage(prog);
  126.                  exit(1);
  127.       }
  128.     }
  129.  
  130.     /** whip past the starting arguments so that we're pointing
  131.         to the right stuff... **/
  132.  
  133.     *argv++;    /* past the program name... */
  134.  
  135.     while (optind-- > 1) {
  136.       *argv++;
  137.       argc--;
  138.     }
  139.  
  140.     /** now let's figure out the parameters to the program... **/
  141.  
  142.     if (argc == 1) {    /* no arguments... called from 'Elm'? */
  143.       if((pass = getpwuid(getuid())) == NULL) {
  144.         printf("You have no password entry!\n");
  145.         exit(1);
  146.       }
  147.       strcpy(home, pass->pw_dir);
  148.       sprintf(filename, "%s/%s", home, readmsg_file);
  149.       if ((file = fopen(filename, "r")) != NULL) {
  150.         fscanf(file, "%d", &(read_message[messages++]));
  151.         fclose(file);
  152.       }
  153.       else {    /* no arguments AND no .readmsg file!! */
  154.             usage(prog);
  155.         exit(1);
  156.       }
  157.     }
  158.     else if (! isdigit(*argv[0]) && *argv[0] != LAST_CHAR &&
  159.              *argv[0] != STAR) {
  160.       string_match++;
  161.  
  162.       while (*argv)
  163.         sprintf(string, "%s%s%s", string, string[0] == '\0'? "" : " ",
  164.             *argv++);
  165.     }
  166.     else if (*argv[0] == STAR)         /* all messages....   */
  167.       list_all_messages++;
  168.     else {                       /* list of nums   */
  169.  
  170.       while (--argc > 0) {
  171.         num = -1;
  172.  
  173.         sscanf(*argv,"%d", &num);
  174.  
  175.         if (num < 0) {
  176.           if (*argv[0] == LAST_CHAR) {
  177.             last_message++;
  178.         num = LAST_MESSAGE;
  179.           }
  180.           else {
  181.             fprintf(stderr,"I don't understand what '%s' means...\n",
  182.             *argv);
  183.                exit(1);
  184.           }
  185.         }
  186.         else if (num == 0) {    /* another way to say "last" */
  187.           last_message++;
  188.           num = LAST_MESSAGE;
  189.         }
  190.  
  191.         *argv++;
  192.  
  193.         read_message[messages++] = num;
  194.       }
  195.  
  196.       /** and now sort 'em to ensure they're in a reasonable order... **/
  197.  
  198.       qsort(read_message, messages, sizeof(int), numcmp);
  199.     }
  200.  
  201.     /** Now let's get to the mail file... **/
  202.  
  203.     if (strlen(infile) == 0) {
  204.       if ((cp = getenv("MAIL")) == NULL) {
  205.         if ((cp = getenv("LOGNAME")) == NULL)
  206.           sprintf(infile, "%s/%s", mailhome, getenv("USER"));
  207.         else
  208.           sprintf(infile, "%s/%s", mailhome, cp);
  209.       }
  210.       else
  211.         strcpy(infile, cp);
  212.     }
  213.  
  214.     if ((file = fopen(infile, "r")) == NULL) {
  215.       printf("But you have no mail! [ file = %s ]\n", infile);
  216.       exit(0);
  217.     }
  218.  
  219.     /** Now it's open, let's display some 'ole messages!! **/
  220.  
  221.     if (string_match || last_message) {   /* pass through it once */
  222.  
  223.       if (last_message) {
  224.         total = count_messages(file);    /* instantiate count */
  225.         for (num=0; num < messages; num++)
  226.           if (read_message[num] == LAST_MESSAGE)
  227.         read_message[num] = total;
  228.       }
  229.       else if (string_match)
  230.         match_string(file, string);        /* stick msg# in list */
  231.  
  232.       if (total == 0 && ! string_match) {
  233.         printf("There aren't any messages to read!\n");
  234.         exit(0);
  235.       }
  236.     }
  237.  
  238.      /** now let's have some fun! **/
  239. #ifdef MMDF
  240.     newheader = 0;
  241. #endif /* MMDF */
  242.  
  243.     while (fgets(buffer, SLEN, file) != NULL) {
  244. #ifdef MMDF
  245.       if (strcmp(buffer, MSG_SEPERATOR) == 0 ||
  246.               !newheader && real_from(buffer))
  247.             newheader = 1; /* !newheader; */
  248.           else
  249.             newheader = 0;
  250.       if (newheader) {
  251. #else
  252.       if (real_from(buffer)) {
  253. #endif /* MMDF */
  254.         if (! list_all_messages) {
  255.           if (current == read_message[current_in_queue])
  256.             current_in_queue++;
  257.           if (current_in_queue >= messages)
  258.             exit(0);
  259.         }
  260.         current++;
  261.         not_in_header = 0;    /* we're in the header! */
  262.       }
  263.  
  264.       if (current == read_message[current_in_queue] || list_all_messages)
  265. #ifdef MMDF
  266.         if ((include_headers==ALL || not_in_header)
  267.         && strcmp(buffer, MSG_SEPERATOR) != 0)
  268. #else
  269.         if (include_headers==ALL || not_in_header)
  270. #endif /* MMDF */
  271.           printf("%s", buffer);
  272.         else if (strlen(buffer) < 2) {
  273.           not_in_header++;
  274.           if (include_headers==WEED)
  275.         list_saved_headers(page_breaks);
  276.         }
  277.         else if (include_headers==WEED)
  278.           possibly_save(buffer);     /* check to see if we want this */
  279.     }
  280.  
  281.     exit(0);
  282. }
  283.  
  284. usage(prog)
  285. char *prog;
  286. {
  287.   printf("\nUsage: %s [-n|-h] [-f filename] [-p] <message list>\n", prog);
  288.   printf("\n  -n   don't print any headers"
  289.          "\n  -h   print all headers"
  290.          "\n  -p   printf form feeds between messages\n"
  291.          "\n  -f filename    use this instead of default mailbox\n");
  292. }
  293.  
  294. int
  295. count_messages(file)
  296. FILE *file;
  297. {
  298.     /** Returns the number of messages in the file **/
  299.  
  300.     char buffer[SLEN];
  301.     int  count = 0;
  302. #ifdef MMDF
  303.     int  newheader = 0;
  304. #endif /* MMDF */
  305.  
  306.     while (fgets(buffer, SLEN, file) != NULL)
  307. #ifdef MMDF
  308.       if (strcmp(buffer, MSG_SEPERATOR) == 0
  309.               || !newheader && real_from(buffer)) {
  310.         newheader = 1;
  311. #else
  312.       if (real_from(buffer)) |
  313. #endif /* MMDF */
  314.         count++;
  315.           }
  316. #ifdef MMDF
  317.           else
  318.         newheader = 0;
  319. #endif /* MMDF */
  320.  
  321.     rewind( file );
  322.     return( count );
  323. }
  324.  
  325. match_string(mailfile, string)
  326. FILE *mailfile;
  327. char *string;
  328. {
  329.     /** Increment "messages" and put the number of the message
  330.         in the message_count[] buffer until we match the specified
  331.         string... **/
  332.  
  333.     char buffer[SLEN];
  334.     int  message_count = 0;
  335. #ifdef MMDF
  336.     int  newheader = 0;
  337. #endif /* MMDF */
  338.  
  339.     while (fgets(buffer, SLEN, mailfile) != NULL) {
  340. #ifdef MMDF
  341.       if (strcmp(buffer, MSG_SEPERATOR) == 0
  342.               || !newheader && real_from(buffer)) {
  343.         newheader = 1;
  344. #else
  345.       if (real_from(buffer)) {
  346. #endif /* MMDF */
  347.         message_count++;
  348.           }
  349. #ifdef MMDF
  350.           else
  351.         newheader = 0;
  352. #endif /* MMDF */
  353.  
  354.       if (in_string(buffer, string)) {
  355.         read_message[messages++] = message_count;
  356.         rewind(mailfile);
  357.         return;
  358.       }
  359.     }
  360.  
  361.     fprintf(stderr,"Couldn't find message containing '%s'\n", string);
  362.     exit(1);
  363. }
  364.  
  365. int
  366. numcmp(a, b)
  367. int *a, *b;
  368. {
  369.     /** compare 'a' to 'b' returning less than, equal, or greater
  370.         than, accordingly.
  371.      **/
  372.  
  373.     return(*a - *b);
  374. }
  375.  
  376. static char from[SLEN], subject[SLEN], date[SLEN], to[SLEN];
  377.  
  378. possibly_save(buffer)
  379. char *buffer;
  380. {
  381.     /** Check to see what "buffer" is...save it if it looks
  382.         interesting... We'll always try to get SOMETHING
  383.         by tearing apart the "From " line...  **/
  384.  
  385.     if (strncmp(buffer, "Date:", 5) == 0)
  386.       strcpy(date, buffer);
  387.     else if (strncmp(buffer, "Subject:", 8) == 0)
  388.       strcpy(subject,buffer);
  389.     else if (strncmp(buffer,"From:", 5) == 0)
  390.       strcpy(from, buffer);
  391.     else if (strncmp(buffer,"To: ", 3) == 0)
  392.       strncpy(to, buffer, SLEN);
  393.     else if (strncmp(buffer,"From ", 5) == 0) {
  394.       sprintf(from, "From: %s\n", words(2,1, buffer));
  395.       sprintf(date,"Date: %s",    words(3,7, buffer));
  396.       to[0] = '\0';
  397.       subject[0] = '\0';
  398.     }
  399. }
  400.  
  401. list_saved_headers(page_break)
  402. int page_break;
  403. {
  404.     /** This routine will display the information saved from the
  405.         message being listed...If it displays anything it'll end
  406.         with a blank line... **/
  407.  
  408.     register int displayed_line = FALSE;
  409.     static int messages_listed = 0;
  410.  
  411.     if (messages_listed++)
  412.       if (page_break)
  413.         putc(FORMFEED, stdout);
  414.       else
  415.         printf(
  416. "\n--------------------------------------------------------------------\n\n\n");
  417.  
  418.     if (strlen(from)    > 0) { printf("%s", from);    displayed_line++;}
  419.     if (strlen(subject) > 0) { printf("%s", subject); displayed_line++;}
  420.     if (strlen(to)      > 0) { printf("%s", to);      displayed_line++;}
  421.     if (strlen(date)    > 0) { printf("%s", date);    displayed_line++;}
  422.  
  423.     if (displayed_line)
  424.        putc('\n', stdout);
  425. }
  426.  
  427. char *words(word, num_words, buffer)
  428. int word, num_words;
  429. char *buffer;
  430. {
  431.     /** Return a buffer starting at 'word' and containing 'num_words'
  432.         words from buffer.  Assume white space will delimit each word.
  433.     **/
  434.  
  435.     static char internal_buffer[SLEN];
  436.     char   *wordptr, *bufptr, mybuffer[SLEN], *strtok();
  437.     int    wordnumber = 0, copying_words = 0;
  438.  
  439.     internal_buffer[0] = '\0';    /* initialize */
  440.  
  441.     strcpy(mybuffer, buffer);
  442.     bufptr = (char *) mybuffer;    /* and setup */
  443.  
  444.     while ((wordptr = strtok(bufptr, " \t")) != NULL) {
  445.       if (++wordnumber == word) {
  446.         strcpy(internal_buffer, wordptr);
  447.         copying_words++;
  448.         num_words--;
  449.       }
  450.       else if (copying_words) {
  451.         strcat(internal_buffer, " ");
  452.         strcat(internal_buffer, wordptr);
  453.         num_words--;
  454.       }
  455.  
  456.       if (num_words < 1)
  457.         return((char *) internal_buffer);
  458.  
  459.       bufptr = NULL;
  460.     }
  461.  
  462.     return( (char *) internal_buffer);
  463. }
  464.  
  465. int
  466. real_from(buffer)
  467. char *buffer;
  468. {
  469.     /***** Returns true iff 's' has the seven 'from' fields, (or
  470.            8 - some machines include the TIME ZONE!!!) *****/
  471.  
  472.     char sixthword[STRING], seventhword[STRING],
  473.          eighthword[STRING], ninthword[STRING];
  474.  
  475.     /* From <user> <day> <month> <day> <hr:min:sec> <year> */
  476.  
  477.     if(strncmp(buffer, "From ", 5) != 0)
  478.       return(FALSE);
  479.  
  480.     /* Extract 6th, 7th, 8th, and 9th words */
  481.     seventhword[0] = eighthword[0] = ninthword[0] = '\0';
  482.     sscanf(buffer, "%*s %*s %*s %*s %*s %s %s %s %s",
  483.       sixthword, seventhword, eighthword, ninthword);
  484.  
  485.     /* Not a from line if 6th word doesn't have colons for time field */
  486.     if(strlen(sixthword) < 3)
  487.       return(FALSE);
  488.     if (sixthword[1] != ':' && sixthword[2] != ':')
  489.       return(FALSE);
  490.  
  491.     /* Not a from line if there is no seventh word */
  492.     if(seventhword[0] == '\0')
  493.       return(FALSE);
  494.  
  495.     /* Not a from line if there is a ninthword */
  496.     if (eighthword[0] != '\0') {
  497.       if(ninthword[0] != '\0')
  498.         return(FALSE);
  499.     }
  500.  
  501.     return(TRUE);
  502. }
  503.