home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / hyprmail.zip / parse.c < prev    next >
C/C++ Source or Header  |  1997-03-16  |  18KB  |  718 lines

  1. /*
  2. ** Copyright (C) 1994, Enterprise Integration Technologies Corp.        
  3. ** All Rights Reserved.
  4. ** Kevin Hughes, kevinh@eit.com 
  5. ** 7/31/94
  6. */
  7.  
  8. #include "hypermail.h"
  9. #include "parse.h"
  10.  
  11. /* Parsing...the heart of Hypermail!
  12. ** This loads in the articles from stdin or a mailbox, adding the right
  13. ** field variables to the right structures. If readone is set, it will
  14. ** think anything it reads in is one article only.
  15. */
  16.  
  17. void loadheaders(mbox, use_stdin, readone)
  18.      char *mbox;
  19.      int use_stdin;
  20.      int readone;
  21. {
  22.     FILE *fp;
  23.     char name[NAMESTRLEN], email[MAILSTRLEN], date[DATESTRLEN],
  24.         msgid[MSGDSTRLEN], subject[SUBJSTRLEN], inreply[REPYSTRLEN],
  25.         line[MAXLINE], tmpfrom[MAXLINE], fromdate[DATESTRLEN],
  26.         oldline[MAXLINE];
  27.     int num, isinheader, hassubject, hasdate, wasinreply;
  28.     struct body *bp;
  29.  
  30.     if (!strcmp(mbox, "NONE") || use_stdin)
  31.         fp = stdin;
  32.     else {
  33.         if ((fp = fopen(mbox, "r")) == NULL) {
  34.             sprintf(errmsg, "Couldn't open mail archive \"%s\".",
  35.             mbox);
  36.             progerr(NULL);
  37.         }
  38.     }
  39.  
  40.     if (readone)
  41.         num = bignum;
  42.     else
  43.         num = 0;
  44.     hassubject = 0;
  45.     hasdate = 0;
  46.     wasinreply = 0;
  47.     isinheader = 1;
  48.     inreply[0] = '\0';
  49.     tmpfrom[0] = '\0';
  50.     oldline[0] = '\0';
  51.     bp = NULL;
  52.     if (!readone) {
  53.         replylist = NULL;
  54.         subjectlist = NULL;
  55.         authorlist = NULL;
  56.         datelist = NULL;
  57.     }
  58.     if (showprogress && readone)
  59.         printf("Reading new header...\n");
  60.     if (showprogress && !readone) {
  61.         if (!strcmp(mbox, "NONE") || use_stdin)
  62.             printf("Loading mailbox...    ");
  63.         else
  64.             printf("Loading mailbox \"%s\"...    ", mbox);
  65.     }
  66.     while (fgets(line, MAXLINE, fp) != NULL) {
  67.         if (isinheader) {
  68.             if (!strncmp(line, "Received:", 9) ||
  69.             !strncmp(line, "Return-Path:", 12) ||
  70.             !strncmp(line, "Cc:", 3) ||
  71.             !strncmp(line, "X-", 2) ||
  72.             !strncmp(line, "Flags:", 6))
  73.                 continue;
  74.             if (!strncmp(line, "From ", 5))
  75.                 strcpy(fromdate, (char *) getfromdate(line));
  76.             else if (!strncmp(line, "Date:", 5)) {
  77.                 bp = (struct body *) addbody(bp, line);
  78.                 strcpy(date, (char *) getmaildate(line));
  79.                 hasdate = 1;
  80.             }
  81.             else if (!strncmp(line, "From:", 5)) {
  82.                 bp = (struct body *) addbody(bp, line);
  83.                 getname(line, name, email);
  84.             }
  85.             else if (!strncmp(line, "Message-Id:", 11)) {
  86.                 bp = (struct body *) addbody(bp, line);
  87.                 strcpy(msgid, (char *) getid(line));
  88.             }
  89.             else if (!strncmp(line, "Subject:", 8)) {
  90.                 bp = (struct body *) addbody(bp, line);
  91.                 strcpy(subject, (char *) getsubject(line));
  92.                 hassubject = 1;
  93.             }
  94.             else if (!strncmp(line, "In-Reply-To:", 12)) {
  95.                 bp = (struct body *) addbody(bp, line);
  96.                 strcpy(inreply, (char *) getreply(line));
  97.                 wasinreply = 1;
  98.             }
  99.             else if ((!strncmp(line, "    ", 4) ||
  100.             line[0] == '\t') &&
  101.             strchr(line, '<') && strchr(line, '>') &&
  102.             strchr(line, '@') && wasinreply) {
  103.                 bp = (struct body *) addbody(bp, line);
  104.                 strcpy(inreply, (char *) getreply(line));
  105.                 wasinreply = 0;
  106.             }
  107.             else if (!strncmp(line, "To:", 3))
  108.                 bp = (struct body *) addbody(bp, line);
  109.             else if (line[0] == '\n') {
  110.                 bp = (struct body *) addbody(bp, line);
  111.                 isinheader = 0;
  112.             }
  113.         }
  114.         else {
  115.             if (!strncmp(line, "From ", 5)) {
  116.                 if (readone)
  117.                     continue;
  118.                 if (strstr(oldline,
  119.                 "Forwarded message:")) {
  120.                     oldline[0] = '\0';
  121.                     continue;
  122.                 }
  123.                 isinheader = 1;
  124.                 wasinreply = 0;
  125.                 if (!hassubject)
  126.                     strcpy(subject, NOSUBJECT);
  127.                 else
  128.                     hassubject = 1;
  129.                 if (!hasdate)
  130.                     strcpy(date, NODATE);
  131.                 else
  132.                     hasdate = 1;
  133.                 if (inreply[0] == '\0')
  134.                     oneunre(inreply, subject);
  135.                 while (rmlastlines(bp));
  136.                 addhash(num, date, name, email, msgid, subject,
  137.                 inreply, fromdate, bp);
  138.                 authorlist = (struct header *)
  139.                 addheader(authorlist, num, name, subject,
  140.                 date, 1);
  141.                 subjectlist = (struct header *)
  142.                 addheader(subjectlist, num, name, unre(subject),
  143.                 date, 0);
  144.                 datelist = (struct header *)
  145.                 addheader(datelist, num, name, subject,
  146.                 fromdate, 2);
  147.                 strcpy(fromdate, (char *) getfromdate(line));
  148.  
  149.                 bp = NULL;
  150.                 num++;
  151.                 if (!(num % 10) && showprogress && !readone) {
  152.                     printf("\b\b\b\b%4d", num);
  153.                     fflush(stdout);
  154.                 }
  155.                 inreply[0] = '\0';
  156.             }
  157.             else
  158.                 bp = (struct body *) addbody(bp, line);
  159.         }
  160.         strcpy(oldline, line);
  161.     }
  162.     if (!isinheader) {
  163.         if (!hassubject)
  164.             strcpy(subject, NOSUBJECT);
  165.         if (!hasdate)
  166.             strcpy(date, NODATE);
  167.         if (inreply[0] == '\0')
  168.             oneunre(inreply, subject);
  169.         while (rmlastlines(bp));
  170.         addhash(num, date, name, email, msgid, subject, inreply,
  171.         fromdate, bp);
  172.         authorlist = (struct header *)
  173.         addheader(authorlist, num, name, subject, date, 1);
  174.         subjectlist = (struct header *)
  175.         addheader(subjectlist, num, name, unre(subject), date, 0);
  176.         datelist = (struct header *) addheader(datelist, num, name,
  177.         subject, fromdate, 2);
  178.         num++;
  179.     }
  180.     if (showprogress && !readone)
  181.         printf("\b\b\b\b%4d articles.\n", num);
  182.  
  183.     if (!readone)
  184.         bignum = num - 1;
  185.     fclose(fp);
  186.  
  187.     crossindex();
  188.  
  189.     threadlist = NULL;
  190.     printedthreadlist = NULL;
  191.     crossindexthread1(datelist);
  192. }
  193.  
  194. /* All this does is get all the relevant header information from the
  195. ** comment fields in existing archive files. Everything is loaded into
  196. ** structures in the exact same way as if articles were being read from
  197. ** stdin or a mailbox.
  198. */
  199.  
  200. void loadoldheaders(dir)
  201.      char *dir;
  202. {
  203.     FILE *fp;
  204.     char name[NAMESTRLEN], email[MAILSTRLEN], date[DATESTRLEN],
  205.         msgid[MSGDSTRLEN], subject[SUBJSTRLEN], inreply[REPYSTRLEN],
  206.         line[MAXLINE], fromdate[DATESTRLEN], filename[MAXFILELEN];
  207.     int num;
  208.     struct body *bp;
  209.  
  210.     num = 0;
  211.     sprintf(filename, "%s%s%.4d.html", dir,
  212.     (dir[strlen(dir) - 1] == '/') ? "" : "/", num);
  213.  
  214.     bp = NULL;
  215.     bp = (struct body *) addbody(bp, "\0");
  216.  
  217.     authorlist = subjectlist = datelist = NULL;
  218.  
  219.     if (showprogress)
  220.         printf("Reading old headers...    ");
  221.     while ((fp = fopen(filename, "r")) != NULL) {
  222.  
  223.         fgets(line, MAXLINE, fp);
  224.         strcpy(fromdate, (char *) getvalue(line));
  225.         fgets(line, MAXLINE, fp);
  226.         strcpy(date, (char *) getvalue(line));
  227.         fgets(line, MAXLINE, fp);
  228.         strcpy(name, (char *) getvalue(line));
  229.         fgets(line, MAXLINE, fp);
  230.         strcpy(email, (char *) getvalue(line));
  231.         fgets(line, MAXLINE, fp);
  232.         strcpy(subject, (char *) unconvchars(getvalue(line)));
  233.         fgets(line, MAXLINE, fp);
  234.         strcpy(msgid, (char *) getvalue(line));
  235.         fgets(line, MAXLINE, fp);
  236.         strcpy(inreply, (char *) unconvchars(getvalue(line)));
  237.  
  238.         fclose(fp);
  239.  
  240.         addhash(num, date, name, email, msgid, subject,
  241.         inreply, fromdate, bp);
  242.         authorlist = (struct header *)
  243.         addheader(authorlist, num, name, subject, date, 1);
  244.         subjectlist = (struct header *)
  245.         addheader(subjectlist, num, name, unre(subject), date, 0);
  246.         datelist = (struct header *)
  247.         addheader(datelist, num, name, subject, fromdate, 2);
  248.  
  249.         num++;
  250.         if (!(num % 10) && showprogress) {
  251.             printf("\b\b\b\b%4d", num);
  252.             fflush(stdout);
  253.         }
  254.  
  255.         sprintf(filename, "%s%s%.4d.html", dir,
  256.         (dir[strlen(dir) - 1] == '/') ? "" : "/", num);
  257.     }
  258.     if (showprogress)
  259.         printf("\b\b\b\b%4d articles.\n", num);
  260.  
  261.     if (!num)
  262.         bignum = 0;
  263.     else
  264.         bignum = num;
  265. }
  266.  
  267. /* Adds a "Next:" link in the proper article, after the archive has been
  268. ** incrementally updated.
  269. */
  270.  
  271. void fixnextheader(dir, num)
  272.      char *dir;
  273.      int num;
  274. {
  275.     char filename[MAXFILELEN], line[MAXLINE], name[NAMESTRLEN],
  276.         email[MAILSTRLEN], subject[SUBJSTRLEN], inreply[REPYSTRLEN],
  277.         date[DATESTRLEN], fromdate[DATESTRLEN], msgid[MSGDSTRLEN];
  278.     struct body *bp, *status;
  279.     FILE *fp;
  280.  
  281.     sprintf(filename, "%s%s%.4d.html", dir,
  282.     (dir[strlen(dir) - 1] == '/') ? "" : "/", num);
  283.  
  284.     bp = NULL;
  285.     if ((fp = fopen(filename, "r")) != NULL) {
  286.         while ((fgets(line, MAXLINE, fp)) != NULL)
  287.             bp = (struct body *) addbody(bp, line);
  288.     }
  289.     else
  290.         return;
  291.     fclose(fp);
  292.  
  293.     if ((fp = fopen(filename, "w+")) != NULL)
  294.         while (bp != NULL) {
  295.             fprintf(fp, "%s", bp->line);
  296.             if (!strncmp(bp->line, "<!-- next=", 10)) {
  297.  
  298.                 status = (struct body *) hashnumlookup(num + 1,
  299.                 name, email, subject, inreply, date, fromdate,
  300.                 msgid);
  301.                 if (status != NULL) {
  302.                 fprintf(fp, "<li> <b>Next message:</b> ");
  303.                 fprintf(fp,
  304.                 "<a href=\"%.4d.html\">%s: \"%s\"</a>\n",
  305.                 num + 1, name, convchars(subject));
  306.                 }
  307.  
  308.             }
  309.             bp = bp->next;
  310.         }
  311.     fclose(fp);
  312. }
  313.  
  314. /* Adds a "Reply:" link in the proper article, after the archive has been
  315. ** incrementally updated.
  316. */
  317.  
  318. void fixreplyheader(dir, num)
  319.      char *dir;
  320.      int num;
  321. {
  322.     int replynum, subjmatch;
  323.     char filename[MAXFILELEN], line[MAXLINE], name[NAMESTRLEN],
  324.         email[MAILSTRLEN], subject[SUBJSTRLEN], inreply[REPYSTRLEN],
  325.         date[DATESTRLEN], fromdate[DATESTRLEN], msgid[MSGDSTRLEN],
  326.         name2[NAMESTRLEN], subject2[SUBJSTRLEN];
  327.     struct body *bp, *status;
  328.     FILE *fp;
  329.  
  330.     status = (struct body *) hashnumlookup(num,
  331.     name, email, subject, inreply, date, fromdate, msgid);
  332.     if (status == NULL || inreply[0] == '\0')
  333.         return;
  334.     if (inreply[0] != '\0') {
  335.         replynum = hashreplylookup(inreply, name2, subject2,
  336.         &subjmatch);
  337.         if (replynum == -1)
  338.             return;
  339.     }
  340.  
  341.     sprintf(filename, "%s%s%.4d.html", dir,
  342.     (dir[strlen(dir) - 1] == '/') ? "" : "/", replynum);
  343.  
  344.     bp = NULL;
  345.     if ((fp = fopen(filename, "r")) != NULL) {
  346.         while ((fgets(line, MAXLINE, fp)) != NULL)
  347.             bp = (struct body *) addbody(bp, line);
  348.     }
  349.     else
  350.         return;
  351.     fclose(fp);
  352.  
  353.     if ((fp = fopen(filename, "w+")) != NULL)
  354.         while (bp != NULL) {
  355.             if (!strncmp(bp->line, "<!-- reply", 10)) {
  356.                 fprintf(fp, "<li> <b>Reply:</b> ");
  357.                 fprintf(fp, "<a href=\"%.4d.html\">", num);
  358.                 fprintf(fp, "%s: \"%s\"</a>\n",
  359.                 name, convchars(subject));
  360.             }
  361.             fprintf(fp, "%s", bp->line);
  362.             bp = bp->next;
  363.         }
  364.     fclose(fp);
  365. }
  366.  
  367. /* Adds a "Next in thread:" link in the proper article, after the archive
  368. ** has been incrementally updated.
  369. */
  370.  
  371. void fixthreadheader(dir, num)
  372.      char *dir;
  373.      int num;
  374. {
  375.     int threadnum;
  376.     char filename[MAXFILELEN], line[MAXLINE], name[NAMESTRLEN],
  377.         subject[SUBJSTRLEN];
  378.     struct body *bp;
  379.     struct reply *rp;
  380.     FILE *fp;
  381.  
  382.     for (rp = threadlist; rp != NULL; rp = rp->next)
  383.         if (rp->next != NULL && rp->next->msgnum == num &&
  384.         rp->msgnum != -1) {
  385.             threadnum = rp->msgnum;
  386.             strcpy(name, rp->next->name);
  387.             strcpy(subject, rp->next->subject);
  388.             break;
  389.         }
  390.     if (rp == NULL)
  391.         return;
  392.  
  393.     sprintf(filename, "%s%s%.4d.html", dir,
  394.     (dir[strlen(dir) - 1] == '/') ? "" : "/", threadnum);
  395.  
  396.     bp = NULL;
  397.     if ((fp = fopen(filename, "r")) != NULL) {
  398.         while ((fgets(line, MAXLINE, fp)) != NULL)
  399.             bp = (struct body *) addbody(bp, line);
  400.     }
  401.     else
  402.         return;
  403.     fclose(fp);
  404.  
  405.     if ((fp = fopen(filename, "w+")) != NULL)
  406.         while (bp != NULL) {
  407.             fprintf(fp, "%s", bp->line);
  408.             if (!strncmp(bp->line, "<!-- nextthr", 12)) {
  409.                 fprintf(fp, "<li> <b>Next in thread:</b> ");
  410.                 fprintf(fp, "<a href=\"%.4d.html\">", num);
  411.                 fprintf(fp, "%s: \"%s\"</a>\n",
  412.                 name, convchars(subject));
  413.             }
  414.             bp = bp->next;
  415.         }
  416.     fclose(fp);
  417. }
  418.  
  419. /* Cross-indexes - adds to a list of replies. If a message is a reply to
  420. ** another, the number of the messge it's replying to is added to the list.
  421. ** This list is searched upon printing.
  422. */
  423.  
  424. void crossindex()
  425. {
  426.     int num, status, maybereply;
  427.     char name[NAMESTRLEN], subject[SUBJSTRLEN], email[MAILSTRLEN],
  428.         inreply[REPYSTRLEN], date[DATESTRLEN], fromdate[DATESTRLEN],
  429.         msgid[MSGDSTRLEN];
  430.  
  431.     num = 0;
  432.     replylist = NULL;
  433.  
  434.     while (hashnumlookup(num, name, email, subject, inreply,
  435.     date, fromdate, msgid) != NULL) {
  436.         if (inreply[0] != '\0') {
  437.             status = hashreplynumlookup(inreply, &maybereply);
  438.             if (status != -1)
  439.                 replylist = (struct reply *)
  440.                 addreply(replylist, status, num, name, subject,
  441.                 maybereply);
  442.         }
  443.         num++;
  444.     }
  445. }
  446.  
  447. /* First, print out the threads in order by date...
  448. ** Each message number is appended to a thread list. Threads and individual
  449. ** messages are separated by a -1.
  450. */
  451.  
  452. void crossindexthread1(hp)
  453.      struct header *hp;
  454. {
  455.         int hasreply;
  456.         struct reply *rp;
  457.  
  458.         if (hp != NULL) {
  459.                 crossindexthread1(hp->left);
  460.  
  461.                 for (hasreply = 0, rp = replylist; rp != NULL; rp = rp->next)
  462.                         if (rp->frommsgnum == hp->msgnum) {
  463.                                 hasreply = 1;
  464.                                 break;
  465.                         }
  466.  
  467.                 if (!hasreply && !wasprinted(printedthreadlist, hp->msgnum)) {
  468.             threadlist = (struct reply *)
  469.             addreply(threadlist, hp->msgnum, hp->msgnum,
  470.             hp->name, hp->subject, 0);
  471.                         crossindexthread2(hp->msgnum);
  472.             threadlist = (struct reply *)
  473.             addreply(threadlist, -1, -1, " ", " ", 0);
  474.         }
  475.  
  476.                 crossindexthread1(hp->right);
  477.         }
  478. }
  479.  
  480. /* Recursively checks for replies to replies to a message, etc.
  481. ** Replies are added to the thread list.
  482. */
  483.  
  484. void crossindexthread2(num)
  485.      int num;
  486. {
  487.         struct reply *rp;
  488.  
  489.         for (rp = replylist; rp != NULL; rp = rp->next)
  490.                 if (rp->msgnum == num) {
  491.             threadlist = (struct reply *)
  492.             addreply(threadlist, rp->frommsgnum, num,
  493.             rp->name, rp->subject, 0);
  494.                         printedlist = (struct printed *)
  495.                         markasprinted(printedthreadlist, rp->frommsgnum);
  496.                         crossindexthread2(rp->frommsgnum);
  497.                 }
  498. }
  499.  
  500. /* Grabs the date string from a Date: header.
  501. */
  502.  
  503. char *getmaildate(line)
  504.      char *line;
  505. {
  506.     int i;
  507.     char *c;
  508.     static char date[DATESTRLEN];
  509.  
  510.     c = (char *) strchr(line, ':');
  511.     if ((*(c + 1) && *(c + 1) == '\n') ||
  512.     (*(c + 2) && *(c + 2) == '\n')) {
  513.         strcpy(date, NODATE);
  514.         return date;
  515.     }
  516.     c += 2;
  517.     while (isspace(*c))
  518.         c++;
  519.     for (i = 0; *c && *c != '\n' && i < DATESTRLEN; c++)
  520.         date[i++] = *c;
  521.     date[i] = '\0';
  522.  
  523.     return date;
  524. }
  525.  
  526. /* Grabs the date string from a From article separator.
  527. */
  528.  
  529. char *getfromdate(line)
  530.      char *line;
  531. {
  532.     int i;
  533.     char *c;
  534.     static char tmpdate[DATESTRLEN];
  535.  
  536.     for (i = 0; days[i] != NULL && (c = (char *) strstr(line, days[i]))
  537.     == NULL; i++)
  538.         ;
  539.     if (days[i] == NULL)
  540.         tmpdate[0] = '\0';
  541.     else {
  542.         for (i = 0; *c && *c != '\n' && i < DATESTRLEN; c++)
  543.             tmpdate[i++] = *c;
  544.         tmpdate[i] = '\0';
  545.         if (tmpdate[16] != ':') {
  546.             tmpdate[16] = ':';
  547.             tmpdate[17] = '0';
  548.             tmpdate[18] = '0';
  549.             tmpdate[19] = ' ';
  550.             tmpdate[20] = thisyear[0];
  551.             tmpdate[21] = thisyear[1];
  552.             tmpdate[22] = thisyear[2];
  553.             tmpdate[23] = thisyear[3];
  554.             tmpdate[24] = '\0';
  555.         }
  556.         sprintf(tmpdate, "%s %s", tmpdate, timezonestr);
  557.         return tmpdate;
  558.     }
  559.  
  560.     return tmpdate;
  561. }
  562.  
  563. /* Grabs the name and email address from a From: header.
  564. ** This could get tricky; I've tried to keep it simple.
  565. */
  566.  
  567. void getname(line, name, email)
  568.      char *line;
  569.      char *name;
  570.      char *email;
  571. {
  572.     int i;
  573.     char *c;
  574.  
  575.     if ((c = (char *) strchr(line, '@')) == NULL) {
  576.         if (strchr(line, '(')) {
  577.             c = (char *) strchr(line, ':') + 1;
  578.             while (isspace(*c))
  579.                 c++;
  580.             for (i = 0; *c && *c != '(' && *c != ' ' &&
  581.             *c != '\n' && i < MAILSTRLEN; c++)
  582.                 email[i++] = *c;
  583.             email[i] = '\0';
  584.         }
  585.         else
  586.             strcpy(email, NOEMAIL);
  587.     }
  588.     else {
  589.         while (*c != ' ' && *c != '<')
  590.             c--;
  591.         c++;
  592.         for (i = 0; *c && *c != '>' && *c != ' ' && *c != '\n' &&
  593.         i < MAILSTRLEN;
  594.         c++)
  595.             email[i++] = *c;
  596.         email[i] = '\0';
  597.     }
  598.  
  599.     if (strchr(line, '<')) {
  600.         c = (char *) strchr(line, ':') + 1;
  601.         while (isspace(*c) || *c == '\"')
  602.             c++;
  603.     }
  604.     else if (strchr(line, '('))
  605.         c = (char *) strchr(line, '(') + 1;
  606.     else {
  607.         if (strcmp(email, NOEMAIL))
  608.             strcpy(name, email);
  609.         else
  610.             strcpy(name, NONAME);
  611.         return;
  612.     }
  613.  
  614.     for (i = 0; *c && *c != '<' && *c != '\"' && *c != ')' &&
  615.     *c != '(' && *c != '\n' && i < NAMESTRLEN; c++)
  616.         name[i++] = *c;
  617.     if (*c == '<' || *c == '(')
  618.         name[--i] = '\0';
  619.     else
  620.         name[i] = '\0';
  621. }
  622.  
  623. /* Grabs the message ID, like <...> from the Message-ID: header.
  624. */
  625.  
  626. char *getid(line)
  627.      char *line;
  628. {
  629.     int i;
  630.     char *c;
  631.     static char msgid[MSGDSTRLEN];
  632.  
  633.     c = (char *) strchr(line, '<') + 1;
  634.     for (i = 0; *c && *c != '>' && *c != '\n' && i < MSGDSTRLEN; c++) {
  635.         if (*c == '\\')
  636.             continue;
  637.         msgid[i++] = *c;
  638.     }
  639.     msgid[i] = '\0';
  640.  
  641.     return msgid;
  642. }
  643.  
  644. /* Grabs the subject from the Subject: header.
  645. */
  646.  
  647. char *getsubject(line)
  648.      char *line;
  649. {
  650.     int i;
  651.     char *c;
  652.     static char subject[SUBJSTRLEN];
  653.  
  654.     c = (char *) strchr(line, ':') + 2;
  655.     while (isspace(*c))
  656.         c++;
  657.     for (i = 0; *c && *c != '\n' && i < SUBJSTRLEN; c++)
  658.         subject[i++] = *c;
  659.     subject[i] = '\0';
  660.     for (i--; i >= 0 && isspace(subject[i]); i--)
  661.         subject[i] = '\0';
  662.  
  663.     if (subject[0] == NULL || isspace(subject[0]) || subject[0] == '\n' ||
  664.     !stricmp(subject, "Re:"))
  665.         strcpy(subject, NOSUBJECT);
  666.  
  667.     return subject;
  668. }
  669.  
  670. /* Grabs the message ID, or date, from the In-reply-to: header.
  671. ** Who knows what other formats are out there...
  672. */
  673.  
  674. char *getreply(line)
  675.      char *line;
  676. {
  677.     int i;
  678.     char *c;
  679.     static char reply[REPYSTRLEN];
  680.  
  681.     if ((c = (char *) strstr(line, "dated: ")) != NULL) {
  682.         c += 7;
  683.         for (i = 0; *c && *c != '.' && *c != '\n' && i < REPYSTRLEN;
  684.         c++)
  685.             reply[i++] = *c;
  686.         reply[i] = '\0';
  687.         return reply;
  688.     }
  689.  
  690.     if ((c = (char *) strchr(line, '<')) != NULL ) {
  691.         c++;
  692.         for (i = 0; *c && *c != '>' && *c != '\n' && i < MSGDSTRLEN;
  693.         c++) {
  694.             if (*c == '\\')
  695.                 continue;
  696.             reply[i++] = *c;
  697.         }
  698.         reply[i] = '\0';
  699.         return reply;
  700.     }
  701.  
  702.     if ((c = (char *) strstr(line, "sage of ")) != NULL) {
  703.         c += 8;
  704.         if (*c == '\"')
  705.             c++;
  706.         for (i = 0; *c && *c != '.' && *c != '\n' && *c != 'f' &&
  707.         i < REPYSTRLEN; c++)
  708.             reply[i++] = *c;
  709.         reply[i] = '\0';
  710.         if (*c == 'f')
  711.             reply[--i] = '\0';
  712.         return reply;
  713.     }
  714.  
  715.     reply[0] = '\0';
  716.     return reply;
  717. }
  718.