home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mm / mm-0.90 / babyl.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-18  |  13.9 KB  |  545 lines

  1. /*
  2.  * Copyright (c) 1986, 1990 by The Trustees of Columbia University in
  3.  * the City of New York.  Permission is granted to any individual or
  4.  * institution to use, copy, or redistribute this software so long as it
  5.  * is not sold for profit, provided this copyright notice is retained.
  6.  */
  7.  
  8. #ifndef lint
  9. static char *rcsid = "$Header: /f/src2/encore.bin/cucca/mm/tarring-it-up/RCS/babyl.c,v 2.2 90/10/04 18:23:30 melissa Exp $";
  10. #endif
  11.  
  12. /* babyl.c: routines to handle babyl format mail files */
  13. /*
  14.  * cache stuff may break if there are two open files.
  15.  * when opening second file, maybe rewind "cf", and free the cache.
  16.  */
  17.  
  18. #include "mm.h"                /* good stuff! */
  19. #include "rd.h"
  20. #include "babyl.h"            /* babylish stuff */
  21.  
  22. #define key "BABYL OPTIONS:"        /* key to babyl format */
  23. #define keysize (sizeof(key)/sizeof(char))-1 /* don't count the null */
  24. #define MSGEND '\037'
  25. #define MSGBEG '\014'
  26. #define EOOH  "*** EOOH ***"
  27. #define FROM  "From:"
  28. #define BABYLHEADER "BABYL OPTIONS:\n\
  29. Version: 5\n\
  30. Note:   This is the header of an rmail file.\n\
  31. Note:   If you are seeing it in rmail,\n\
  32. Note:    it means the file has no messages in it.\n\
  33. Labels:"
  34.  
  35.  
  36. extern int local_close();
  37. char *fgetline(), *safe_strcpy();
  38. u_long flaglookup();
  39. static char *cache = 0;
  40.  
  41. static struct flagword flagnames[] = {
  42.     { "deleted", M_DELETED },
  43.     { "answered", M_ANSWERED },
  44.     { "filed", M_FILED },
  45.     { "forwarded", M_FORWARDED },
  46.     { "unseen", M_SEEN },
  47.     { "edited", M_EDITED },
  48.     { NULL, 0 },
  49. };
  50.  
  51.  
  52. static struct flagword keynames[] = {
  53.     { "flagged", M_FLAGGED },
  54.     { NULL, 0 },
  55. };
  56.  
  57. /*
  58.  * babyl_open:
  59.  * see rd.h comments about open
  60.  */
  61. babyl_open(mail,flags)
  62. msgvec *mail;
  63. int flags;
  64. {
  65.     int error;
  66.     struct stat sbuf;
  67.     keylist k;
  68.     struct flagword *fl;
  69.  
  70.     if (!(flags & OP_APP))        /* don't worry if just an append */
  71.     mail->keywords = nil;
  72.     error = local_contig_open (mail,flags);
  73.     if (error != 0 || !(flags & OP_APP))
  74.     return(error);
  75.     if (mail->filep == NULL)        /* reuse cf, file lock downgraded */
  76.     return(0);
  77.     if (fstat(fileno(mail->filep), &sbuf) != 0) {
  78.     perror("fstat");
  79.     return(errno);
  80.     }
  81.     if (sbuf.st_size != 0) 
  82.     return(0);
  83.     fprintf(mail->filep,"%s", BABYLHEADER);
  84.     for(fl = keynames; fl && fl->name; fl++)
  85.     fprintf(mail->filep, "%s%s", fl->name, (fl+1)->name ? "," : "");
  86.     if (mail->keywords && keynames[0].name)
  87.         fputc (',', mail->filep);
  88.     if (mail->keywords)
  89.     for(k = mail->keywords; *k != NULL; k++) 
  90.         fprintf(mail->filep, "%s%s", *k, *(k+1) ? "," : "\n");
  91.     else 
  92.         fputc ('\n', mail->filep);
  93.     fputc (MSGEND, mail->filep);
  94.     return(0);
  95. }
  96.  
  97. /*
  98.  * see rd.h comments about close
  99.  */
  100. babyl_close (fp)
  101. FILE *fp;
  102. {
  103.     local_close (fp);
  104.     if (cache) {
  105.     free(cache);
  106.     cache = NULL;
  107.     }
  108. }
  109.  
  110. /*
  111.  * babyl_rdmsg:
  112.  * see rd.h comments about rd_msg
  113.  */
  114. babyl_rdmsg(mail,num)
  115. msgvec *mail;
  116. int num;
  117. {
  118.     char *babyl_banner();
  119.     char *header, *cp, *text, *htext();
  120.     int buflen, space, eof, line, seen_eooh = false, which_headers = 0;
  121.     message *m;
  122.     u_long size;
  123.  
  124.     if (num > mail->count)        /* much more than we have */
  125.        return (RD_FAIL);        /* not there */
  126.  
  127.     if (mail->last_read > num) {     /* gotta go back to it */
  128.         rewind (mail->filep);        /* have to start from beginning */
  129.     if (cache) {
  130.         free(cache);
  131.         cache = NULL;
  132.     }
  133.     mail->last_read = 0;        /* haven't read msg 1 */
  134.     header = babyl_banner(mail);
  135.     if (header == NULL)
  136.         return(RD_FAIL);        /* no banner, bad file */
  137.     }
  138.     else {                /* no need to rewind */
  139.     if (cache) {
  140.         header = cache;
  141.         cache = NULL;
  142.     }
  143.     else
  144.         header = fgetline(mail->filep);
  145.     if (header == NULL)
  146.         return (RD_EOF);        /* this is the end... */
  147.     if (strcmp(header, key) == 0) {    /* looking at babyl header */
  148.         rewind(mail->filep);
  149.         mail->last_read = 0;
  150.         header = babyl_banner(mail); /* get past banner */
  151.         if (header == NULL) {
  152.         fprintf(stderr,
  153.                "Babyl banner has bad format, ignoring rest of file\n");
  154.         return(RD_FAIL);    /* bad banner, bad file */
  155.         }
  156.     }
  157.     if (header[0] != MSGEND) {
  158.         fail_msg (mail->last_read);
  159.         fseek(mail->filep, -strlen(header), SEEK_CUR);
  160.         return(RD_FAIL);        /* bad previous message */
  161.     }
  162.     }
  163.     
  164.     while (++mail->last_read < num) {    /* skip up to the num'th message */
  165.     if (header[1] != MSGBEG) {
  166.         fseek(mail->filep, -strlen(header), SEEK_CUR);
  167.         free(header);
  168.         fail_msg (mail->last_read--); /* couldn't read it */
  169.         return (RD_FAIL);        /* earlier message missing */
  170.     }
  171.     while (true) {            /* skip one message */
  172.         free(header);
  173.         header = fgetline(mail->filep);
  174.         if (header == NULL) {
  175.         fail_msg (mail->last_read--); /* couldn't read it */
  176.         return (RD_FAIL);    /* bad file -- ended w/out MSGEND */
  177.         }
  178.         if (header[0] == MSGEND)
  179.         break;
  180.     }
  181.     }
  182.     /* should be looking at our msg now */
  183.     if (header[1] != MSGBEG) {        /* no next message.... */
  184.     fseek(mail->filep, -strlen(header), SEEK_CUR);
  185.     free(header);
  186.     if (header[1] != '\0') {    /* not just end of file */
  187.         fail_msg (mail->last_read--); /* couldn't read it */
  188.         return (RD_FAIL);
  189.     }
  190.     return(RD_EOF);            /* just missed it */
  191.     }
  192.     free(header);            /* free "MSGEND MSGBEG \n" */
  193.     header = fgetline(mail->filep);    /* get line with flags and keywords */
  194.                     /* handle babyl flags/keywords */
  195.     if (header[0] == '0')        /* no headers before EOOH */
  196.     which_headers = 2;
  197.     else if (header[0] == '1')
  198.     which_headers = 1;
  199.     else {
  200.     free (header);
  201.     fail_msg (mail->last_read--);
  202.     return (RD_FAIL);        /* bad format */
  203.     }
  204.     mail->msgs[num].keywords = nil;
  205.     if (!babyl_flags(mail,header,&mail->msgs[num])) {
  206.     free(header);
  207.     fail_msg (mail->last_read--);
  208.     return(RD_FAIL);
  209.     }
  210.     free(header);
  211.                     /* now get the rest of the message */
  212.     buflen = 0;
  213.     text = cp = malloc (buflen += 100);    /* get some space for body of msg */
  214.     space = buflen;            /* all empty so far */
  215.     eof = false;            /* not the end yet */
  216.     
  217.     do {
  218.     line = cp - text;        /* starting a line */
  219.  
  220.     if (space < 10) {
  221.         text = (char *) realloc (text, buflen += 100);
  222.         space += 100;        /* used the rest (but for '\0') */
  223.         cp = &text[buflen-space];    /* room to complete line */
  224.     }
  225.     if (fgets (cp, space, mail->filep) == NULL) { /* try to get a line */
  226.         eof = true;            /* end of file, that's it */
  227.         continue;            /* go down to the "while" */
  228.     }
  229.     while (index (cp, '\n') == NULL) {
  230.         text = (char *) realloc (text, buflen +=100);
  231.         space = 101;        /* used the rest (but for '\0') */
  232.         cp = &text[buflen-space];    /* room to complete line */
  233.         if (fgets (cp, space, mail->filep) == NULL) {
  234.             eof = true;        /* end of file */
  235.         break;            /* out of while */
  236.         }
  237.     }
  238.                     /* end of first header? */
  239.     if (eof)
  240.         continue;
  241.     if (text[line] == MSGEND)
  242.         continue;
  243.  
  244.     if (!seen_eooh && (ustrncmp (&text[line], EOOH, strlen(EOOH)) == 0)) {
  245.         seen_eooh = true;
  246.         if (which_headers == 1) {
  247.         text[line] = '\0';        /* forget this line */
  248.         space = space + (cp - &text[line]);    /* reclaim that */
  249.         cp = &text[line];        /* back to beginning */
  250.         while(true) {
  251.             header = fgetline(mail->filep);
  252.             if (strlen(header) == 0) {
  253.             free(header);
  254.             break;
  255.             }
  256.             free(header);
  257.         }
  258.         }
  259.         else {
  260.         text[line] = '\0';        /* forget this line */
  261.         space = space + (cp - &text[line]);    /* reclaim that */
  262.         cp = &text[line];        /* back to beginning */
  263. /*         free(header); */
  264.         continue;
  265.         }
  266.     }
  267.     else if (!seen_eooh && which_headers == 2) {
  268.         text[line] = '\0';        /* forget this line */
  269.         space = space + (cp - &text[line]);    /* reclaim that */
  270.         cp = &text[line];        /* back to beginning */
  271. /*         free(header); */
  272.         continue;
  273.     }
  274.     else {
  275.         while (*cp)            /* get to null */
  276.             cp++;            /* keep going */
  277.         space = buflen - (cp - text); /* what we haven't used */
  278.     }
  279.     } while (!eof && (text[line] != MSGEND));
  280.  
  281.     if (!eof) {
  282.     cache = (char *)safe_strcpy(&text[line]);
  283.     if (text[line] == MSGEND)
  284.         text[line] = '\0';        /* throw it out */
  285.     text = (char *) realloc (text, (size = line) +1); /* snug to fit */
  286.     }
  287.     else {
  288.     if (text[line] == MSGEND)
  289.         text[line] = '\0';        /* throw it out */
  290.         text = (char *) realloc (text, (size = (strlen (text))) +1);
  291.     }
  292.  
  293.  
  294.     m = &mail->msgs[num];
  295.     cp = htext("date", text);
  296.     if (cp) {
  297.     m->date = babyl_date(cp);
  298.     free(cp);
  299.     }
  300.     else 
  301.     m->date = 0;
  302.     if (m->date == 0)
  303.         fprintf (stderr,"Message %d has bad date string (continuing)\n", num);
  304.  
  305.     m->from = NULL;
  306.     m->size = size;
  307.     m->text = text;
  308.     set_msg_keywords(m);
  309.     return (RD_OK);            /* got the message! */
  310. }
  311.  
  312.  
  313. /*
  314.  * babyl_wrmsg:
  315.  * see rd.h comments about wr_msg
  316.  * Each babyl format message starts with a special MSGBEG character.
  317.  * The next line has a "0" to signify that what comes next is
  318.  * unprocessed (as far as true babyl is concerned) headers, with any
  319.  * keywords and flags (as text strings) on the same line as the "0".
  320.  *
  321.  * Next is a "Summary-line:" header if that was in the text, then the
  322.  * special EOOH (End Of, Oh... Headers) string, then the entire text of
  323.  * the message (except for the "Summary-line:"). 
  324.  *
  325.  * Last comes the special MSGEND character.
  326.  *
  327.  */
  328. babyl_wrmsg(mail,msg,num,flags)
  329. msgvec *mail;
  330. message *msg;
  331. int num;
  332. int flags;
  333. {
  334.   int err;
  335.   char *text;
  336.   char *htext();
  337.   struct flagword *fl;
  338.   char **k;
  339.   char *sl, *sl_end;
  340.  
  341.   if (!(flags & (WR_SAVE | WR_COPY))) {    /* not a save or copy */
  342.       mail->flags |= MF_DIRTY;        /* mark it to be saved */
  343.       return (false);            /* no error */
  344.   }
  345.   if ((msg->flags & M_DELETED) && (flags & WR_EXP)) {
  346.       if (num == mail->count)
  347.       local_get_size(mail);
  348.       return (false);            /* don't save deleted messages */
  349.   }
  350.  
  351.   fprintf(mail->filep, "%c\n", MSGBEG);
  352.   fprintf(mail->filep,"0,");
  353.  
  354.   msg->flags ^= M_SEEN;            /* this one works backwards */
  355.   for(fl = flagnames; fl->name != NULL; fl++) {
  356.       if (msg->flags & fl->flag)
  357. #ifdef BROKEN_BABYL
  358.       fprintf(mail->filep, "%s,", fl->name);
  359. #else
  360.       fprintf(mail->filep, " %s,", fl->name); /* space before keyword */
  361. #endif /* BROKEN_BABYL */
  362.   }
  363.   msg->flags ^= M_SEEN;            /* this one works backwards */
  364.  
  365.   fputc(',', mail->filep);
  366.   for(fl = keynames; fl->name != NULL; fl++) {
  367.       if (msg->flags & fl->flag)
  368. #ifdef BROKEN_BABYL
  369.       fprintf(mail->filep, "%s,", fl->name);
  370. #else
  371.       fprintf(mail->filep, " %s,", fl->name); /* space */
  372. #endif /* BROKEN_BABYL */
  373.   }
  374.   for(k = msg->keywords; k && *k; k++)
  375. #ifdef BROKEN_BABYL
  376.       fprintf(mail->filep,"%s,",*k);
  377. #else
  378.       fprintf(mail->filep," %s,",*k);    /* space */
  379. #endif /* BROKEN_BABYL */
  380.   fputc('\n', mail->filep);
  381.   text = msg->text;
  382.   if ((sl = (char *) hfind("summary-line",text)) != NULL) {
  383.       sl_end = index(sl,'\n');
  384.       if (sl_end) *sl_end = '\0';
  385.       fprintf(mail->filep,"%s\n", sl);
  386.       if (sl_end) *sl_end = '\n';
  387.   }
  388.   fprintf(mail->filep,"%s\n",EOOH);
  389.   while(true) {
  390.       char *cp;
  391.       if (text == sl)            /* don't print summary-line */
  392.       text = sl_end+1;
  393.       cp = index(text,'\n');
  394.       if (cp) {
  395.       *cp = '\0';
  396.       fprintf(mail->filep,"%s\n",text);
  397.       if (strlen(text) == 0) {
  398.           *cp = '\n';
  399.           text = cp+1;
  400.           break;
  401.       }
  402.       *cp = '\n';
  403.       text = cp+1;
  404.       }
  405.       else {
  406.       fprintf(mail->filep,"%s",text);
  407.       break;
  408.       }
  409.   }
  410.  
  411.   fwrite(text, sizeof(char), strlen(text), mail->filep);
  412.   fputc(MSGEND, mail->filep);
  413.   if ((fflush (mail->filep) == EOF) ||    /* make sure we get it out */
  414.       (ferror(mail->filep) != 0))
  415.       return (true);
  416.   if (flags & WR_SAVE) {        /* we saved it */
  417.       msg->flags &= ~M_MODIFIED;    /* it's not modified anymore  */
  418.       if (num == mail->count)
  419.       local_get_size(mail);
  420.   }
  421.   return (false);            /* no error */
  422. }
  423.  
  424. /*
  425.  * probe file to see if it's in babyl format
  426.  * babyl format files are distinguished by starting with "BABYL OPTIONS"
  427.  */
  428. babyl_probe (file)
  429. char *file;
  430. {
  431.     FILE *fp;
  432.     char p[keysize +1];        /* enough to probe it, with null */
  433.     int i;
  434.     int ret;
  435.  
  436.     if (cf && same_file(cf->filename, file)) {
  437.     if (cf->type == TYPE_BABYL) 
  438.         return (PR_OK);
  439.     else
  440.         return (PR_NOTOK);
  441.     }
  442.     if ((ret = local_contig_proben (file, &fp)) != PR_OK)
  443.     return (ret);            /* couldn't open it */
  444.     i = fread (p, sizeof (char), keysize, fp);
  445.     fclose (fp);            /* okay, we're done looking */
  446.     if (i == 0)
  447.     return (PR_EMPTY);        /* nothing in it */
  448.     if (i < keysize) 
  449.         return (PR_NOTOK);        /* not enough characters */
  450.     p[i] = '\0';            /* finish the string */
  451.     if (strcmp (p, key) != 0)
  452.         return (PR_NOTOK);        /* doesn't look right */
  453.     return (PR_OK);            /* passed! */
  454. }
  455.  
  456.  
  457. babyl_flags(mail,str, msg)
  458. char *str;
  459. message *msg;
  460. msgvec *mail;
  461. {
  462.     int num;
  463.     u_long f;
  464.     char *ptr;
  465.     keylist add_keyword();
  466.     keylist kw;
  467.     u_long flags;
  468.     int keycount;
  469.     
  470.     keycount = 0;
  471.     flags=0;
  472.     kw = NULL;
  473.     if (!(ptr = index(str, ',')))
  474.     return(false);
  475.     *ptr = '\0';
  476.     num = atoi(str);
  477.     if (num == 0 && str[0] != '0')
  478.     return(false);
  479.     *ptr = ',';
  480.     str = ptr + 1;
  481.  
  482.     while(ptr = index(str,',')) {
  483.     if (*str != ',') {
  484.         *ptr = '\0';
  485.         if (*str == ' ')        /* ignore leading space */
  486.             str++;            /*   see BROKEN_BABYL stuff */
  487.         f = flaglookup(str,flagnames);
  488.         if (f == 0)
  489.         f = flaglookup(str,keynames);
  490.         if (f == 0) {
  491.         kw = add_keyword(str,kw);
  492.         mail->keywords = add_keyword(str,mail->keywords);
  493.         }
  494.         else
  495.         flags |= f;
  496.         *ptr = ',';
  497.     }
  498.     str = ptr + 1;
  499.     }
  500.     msg->flags = flags ^ M_SEEN;    /* this one's backwards */
  501.     msg->keybits = 0;            /* no keybits in babyl format */
  502.     msg->keywords = kw;
  503.     return(true);
  504. }
  505.  
  506. u_long
  507. flaglookup(str,table) 
  508. char *str;
  509. struct flagword *table;
  510. {
  511.     while(table->name) {
  512.     if (ustrcmp(table->name, str) == 0)
  513.         return(table->flag);
  514.     table++;
  515.     }
  516.     return(0);
  517. }
  518.  
  519. /*
  520.  * babyl_banner:
  521.  * skip past the banner, and return a pointer to the MSGEND MSGBEG line
  522.  * before the first message
  523.  * return NULL if something goes wrong...
  524.  */
  525. char *
  526. babyl_banner(mail) 
  527. msgvec *mail;
  528. {
  529.     char *h;
  530.     rewind(mail->filep);
  531.     h = fgetline(mail->filep);
  532.     if (strcmp(h,key) != 0) {
  533.     free(h);
  534.     return(NULL);
  535.     }
  536.     while(true) {
  537.     free(h);
  538.     h = fgetline(mail->filep);
  539.     if (h == NULL) 
  540.         return(NULL);
  541.     if (h[0] == MSGEND)
  542.         return(h);
  543.     }
  544. }
  545.