home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / INTERNET / USENET / PAPERBOY / SOURCE.ZIP / MSGS.C < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-02  |  14.3 KB  |  709 lines

  1. /*      msgs.c -- Handle all sorts of message formats
  2.     This file is part of Paperboy, an offline mail/newsreader for Windows
  3.     Copyright (C) 1994  Michael H. Vartanian
  4.         vart@clark.net
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. */
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <time.h>
  23. #include <stdlib.h>
  24. #include <ctype.h>
  25. #include "soup.h"
  26. #include "error.h"
  27. #include "areas.h"
  28. #include "structs.h"
  29. #include "msgs.h"
  30. #include "unixmail.h"
  31. #include "reclaim.h"
  32.  
  33. extern char * packetpath;       /* base directory for files */
  34.  
  35. struct lltext * msghead=NULL;
  36.  
  37. struct stextcache
  38. {
  39.     int line;
  40.     struct lltext * curline;
  41. } textcache;
  42.  
  43. int convmonth(char * inmonth)
  44. {
  45.     int k;
  46.  
  47.     for (k=0; k<=11; k++)
  48.     {
  49.         if (!strcmp(inmonth,months[k])) break;
  50.     }
  51.  
  52.     return k;       /* If month not found, returns December? */
  53. }
  54.  
  55. void makeidate (struct llmsg * cur)
  56. /* Convert date string to time_t */
  57. {
  58.     char * basedate, * freeme;
  59.     time_t idate;
  60.     struct tm hold;
  61.     char month[4];
  62.     int mday=1, year=94, hour=8, min=30, sec=0;
  63.     char * p;
  64.  
  65.     assert (cur!=NULL);
  66.     assert (cur->date!=NULL);
  67.     if (cur->date==NULL) 
  68.     {
  69.         cur->idate=0;   /* Zulu */
  70.         return;
  71.     }
  72.     
  73.     assert (strlen(cur->date)!=0);
  74.     freeme=strdup(cur->date);
  75.     basedate=freeme;
  76.     /* Skip over blanks, and any day-of-week stuff */
  77.     while (*basedate && !isdigit(*basedate)) basedate++;
  78.  
  79.     p=strtok(basedate," ");
  80.     if (p!=NULL) mday=atoi(p);
  81.     p=strtok(NULL," ");
  82.     if (p!=NULL) strcpy(month,p);
  83.     p=strtok(NULL," ");
  84.     if (p!=NULL) year=atoi(p);
  85.     p=strtok(NULL,":");
  86.     if (p!=NULL) hour=atoi(p);
  87.     p=strtok(NULL,":");
  88.     if (p!=NULL) min =atoi(p);
  89.     p=strtok(NULL,":");
  90.     if (p!=NULL) sec =atoi(p);
  91.  
  92.     if (year>1900) year-=1900;
  93.     hold.tm_mday=mday;
  94.     hold.tm_year=year;
  95.     hold.tm_hour=hour;
  96.     hold.tm_min=min;
  97.     hold.tm_sec=sec;
  98.     hold.tm_wday=0;
  99.     hold.tm_yday=0;
  100.     hold.tm_isdst=0;
  101.     hold.tm_mon=convmonth(month);
  102.  
  103.     idate=mktime(&hold);    
  104.     cur->idate=idate;
  105.     cur->thread_idate=idate;
  106.     free (freeme);
  107. /*      printf("\t\tIN:%s\n\t\tOUT:(%d)%s\n",cur->date,idate,ctime(&idate)); */
  108. }
  109.  
  110. int getstarts (FILE * fin, struct llareas * area)
  111. {
  112.     char line[MAXLINE];
  113.     long length;
  114.     struct llmsg * cur;
  115.  
  116.     assert(fin!=NULL);
  117.     assert(area!=NULL);
  118.     assert(area->head==NULL);
  119.  
  120.     rewind(fin);
  121.  
  122.     while (!feof(fin))
  123.     {
  124.         /* Get start and end of message */
  125.         fgetlf(sizeof(line)-1,fin,line);
  126.         if (feof(fin)) break;
  127.         length=atol(&line[strlen(RNEWSHEAD)+1]);
  128.         if (length==0) return ERRPARSE;
  129.         if (length>0)   /* valid message */
  130.         {
  131.             /* Add to head of linked list */
  132.             cur=(struct llmsg *)malloc(sizeof(struct llmsg));
  133.             if (cur==NULL) return ERRMEM;
  134.             memset(cur,0,sizeof(struct llmsg));     /* zero it out */
  135.             cur->magic=MSGMAGIC;
  136.             cur->next=area->head;
  137.             area->head=cur;
  138.             cur->start=ftell(fin); /* file pointer is after #! rnews n\n */
  139.             cur->length=length;
  140.             fseek(fin,length,SEEK_CUR);     /* Next message */
  141.         }
  142.     }
  143.  
  144.     return 0;
  145. }
  146.  
  147.  
  148. int getheaders (FILE * fin, struct llareas * area)
  149. {
  150.     struct llmsg * cur;
  151.     char line[MAXLINE];
  152.  
  153.     /* Go back and get headers (subject, author, etc. ) */
  154.     cur=area->head; /* First message  */
  155.     while (cur!=NULL)
  156.     {
  157.         fseek(fin,cur->start,SEEK_SET); /* go to start of message */
  158.         do
  159.         {
  160.             fgetlf(sizeof(line)-1,fin,line);        /* Read a line */
  161.             extractvalue (line,SUBJSTR,&(cur->subject));
  162.             extractvalue (line,FROMSTR,&(cur->author));
  163.             extractvalue (line,DATESTR,&(cur->date));
  164.         }
  165.         while ( ( (!cur->date) || (!cur->author) || (!cur->subject) ) && (*line!='\0') );    /* End of headers */
  166.         
  167.         if (cur->subject==NULL) cur->subject=strdup("Subject Unknown");
  168.         if (strlen(cur->subject)>999) cur->subject[999]='\0';
  169.         if (cur->author==NULL) cur->author=strdup("Author Unknown");
  170.         if (cur->date==NULL) cur->date=strdup("01 Jan 1994 08:00:00 EST");
  171.         makeidate(cur);
  172.         cur=cur->next;
  173.     }
  174.     return 0;
  175. }
  176.  
  177. int parsernews (struct llareas * area)
  178. {
  179. /*      A USENET message file has a header of the form "#! rnews n"
  180.     where n is the number of bytes in the message, following the
  181.     LF character after the header.
  182. */
  183.     FILE * fin;
  184.     int     result;
  185.  
  186.     area->head=NULL;        /* No message yet */
  187.  
  188.  
  189.     /*      Open the file */
  190.     assert(area->prefix!=NULL);
  191.     fin=fopen(area->prefix,"rb");  /* MS-DOS likes it binary */
  192.     if (fin==NULL) return ERRIO;
  193.  
  194.     result=getstarts(fin,area);     /* An index file would definetly have this */
  195.     if (result) return result;
  196.  
  197.     result=getheaders(fin,area);    /* An index file might have this */
  198.     if (result) return result;
  199.  
  200.     fclose(fin);
  201.     return 0;
  202. }
  203.  
  204.  
  205. int extractvalue (char * line, char * header, char ** result)
  206. {
  207.     char * value;
  208.     char * newvalue;
  209.     char fullheader[50];
  210.  
  211.     assert (line!=NULL);
  212.     assert (header!=NULL);
  213.     assert (result!=NULL);
  214.     
  215.     strncpy(fullheader,header,45);    /* Make foo into foo:_ */
  216.     strcat(fullheader,": ");
  217.  
  218.     /* Searches line for header, placing rest into result */
  219.     if (_strnicmp(line,fullheader,strlen(fullheader))==0)     /* Match? */
  220.     {
  221.         value=strchr(line,':')+2;    /* Value points to the value after "header: " */
  222.         while (*value==' ') value++;            /* Skip leading spaces */
  223.         assert (value!=NULL);
  224.         assert (strlen(value)!=0);
  225.         newvalue=strdup(value);
  226.         assert(newvalue!=NULL);
  227.         if (newvalue==NULL) return ERRMEM;
  228.         *result=newvalue;
  229.     }
  230.  
  231.     return 0;
  232. }
  233.  
  234. int parsemsg (struct llareas * area)
  235. {
  236.     int result;
  237.  
  238.     assert(area!=NULL);
  239.  
  240.     /* If we've already read in messages, skip processing */
  241.     if (area->head!=NULL) return 0;
  242.     
  243.     result=0;
  244.  
  245.     switch (area->encoding[0])
  246.     {
  247.         case RNEWSTYPE:
  248.         {
  249.             result=parsernews (area);
  250.             break;
  251.         }
  252.         case MAILTYPE:
  253.         {
  254.             result=parseunixmail (area);
  255.             break;
  256.         }
  257.         case MAILMMDF:
  258.         {
  259.             result=ERRPARSE;
  260.             break;
  261.         }
  262.         case BINMAIL:
  263.         {
  264.             result=parsebinmail (area);
  265.             break;
  266.         }
  267.         default:
  268.             result=ERRPARSE;
  269.     }
  270.                                                   
  271.     return result;
  272. }
  273.  
  274. struct llmsg * findmsg (int areaindex, int msgindex)
  275. {
  276.     struct llareas * area;
  277.     struct llmsg * cur;
  278.     int count;
  279.  
  280.     assert (areaindex>0);
  281.     assert (msgindex>0);
  282.     assert (areaindex<=GetNumAreas());
  283.     assert (msgindex<=GetNumMsgs(areaindex));
  284.  
  285.     area=findarea(areaindex);
  286.     cur=area->head;
  287.     count=1;
  288.     while ( (count!=msgindex) && (cur!=NULL) )
  289.     {
  290.         cur=cur->next;
  291.         count++;
  292.     }
  293.  
  294.     assert (cur!=NULL);
  295.  
  296.     return cur;
  297. }
  298.  
  299.  
  300. char * DLLFUNC GetSubject (int areaindex, int msgindex)
  301. {
  302.     struct llmsg * cur;
  303.  
  304.     cur=findmsg(areaindex,msgindex);
  305.     return cur->subject;
  306. }
  307.  
  308.  
  309. char * DLLFUNC GetAuthor (int areaindex, int msgindex)
  310. {
  311.     struct llmsg * cur;
  312.  
  313.     cur=findmsg(areaindex,msgindex);
  314.     return cur->author;
  315. }
  316.  
  317.  
  318. char * DLLFUNC GetDate (int areaindex, int msgindex)
  319. {
  320.     struct llmsg * cur;
  321.  
  322.     cur=findmsg(areaindex,msgindex);
  323.     return cur->date;
  324. }
  325.  
  326.  
  327. long DLLFUNC GetLength (int areaindex, int msgindex)
  328. {
  329.     struct llmsg * cur;
  330.     
  331.     cur=findmsg(areaindex,msgindex);
  332.     return cur->length;
  333. }
  334.  
  335. int DLLFUNC GetNumMsgs (int index)
  336. {
  337.     struct llareas * area;
  338.     struct llmsg * cur;
  339.     int count;
  340.  
  341.     assert (index>0);
  342.     assert (index<=GetNumAreas());
  343.  
  344.     area=findarea(index);
  345.     cur=area->head;
  346.     
  347.     count=0;
  348.     while (cur!=NULL)
  349.     {
  350.         cur=cur->next;
  351.         count++;
  352.     }
  353.  
  354.     return count;
  355. }
  356.  
  357. void clearcache(void)
  358. {
  359.     textcache.line=-9;
  360.     textcache.curline=NULL;
  361. }
  362.  
  363. void purgetext (void)
  364. {
  365. /* Free up old message text */
  366.     struct lltext * next;
  367.  
  368.      clearcache();
  369.     
  370.     while (msghead!=NULL)
  371.     {
  372.         next=msghead->next;
  373.         if (msghead->text!=NULL) free (msghead->text);
  374.         free(msghead);
  375.         msghead=next;
  376.     }
  377. }
  378.  
  379.  
  380. int stuffmessage(FILE * fin, long start, long length)
  381. {
  382.     char line[MAXLINE];
  383.     struct lltext * new, * tail;
  384.     int result;
  385.  
  386.     clearcache();
  387.     
  388.     /* Go to start of message */
  389.     result=fseek(fin,start,SEEK_SET);
  390.     if (result!=0) return ERRIO;
  391.  
  392.     while ( ftell(fin) - start <  length )
  393.     {
  394.         /* get next line in message */
  395.         fgetlf(sizeof(line),fin,line);
  396.  
  397.         /* Create new line node */
  398.         new=(struct lltext *)malloc(sizeof(struct lltext));
  399.         if (new==NULL) return ERRMEM;
  400.         memset(new,0,sizeof(struct lltext));    /* Zero it out */
  401.  
  402.         /* add to tail of linked list */
  403.         if (msghead==NULL)
  404.         {
  405.             msghead=new;
  406.         }
  407.         else
  408.         {
  409.             tail->next=new;
  410.         }
  411.         tail=new;
  412.  
  413.         /* Copy message text into beast */ 
  414.         assert (line!=NULL);
  415.         /* assert (strlen(line)!=0); */
  416.         /* assert (strlen(line)<999); */
  417.         if (strlen(line)>999) line[999]='\0';   /* Truncate line after 999 characters */
  418.         new->text=strdup(line);
  419.         if (new->text==NULL) return ERRMEM;
  420.     }
  421.     return 0;
  422. }
  423.  
  424.  
  425. int loadtext (struct llareas * area,struct llmsg * msg)
  426. {
  427.     FILE * fin;
  428.     int result;
  429.  
  430.     assert(msghead==NULL);  /* Previous text should've been purged */
  431.  
  432.     /*      Open the file */
  433.     assert(area->prefix!=NULL);
  434.     fin=fopen(area->prefix,"rb");  /* MS-DOS likes it binary */
  435.     if (fin==NULL) return ERRIO;
  436.  
  437.     result=stuffmessage(fin,msg->start,msg->length);
  438.     if (result) return result;
  439.  
  440.     fclose (fin);
  441.  
  442.     return 0;
  443. }
  444.  
  445. void DLLFUNC CreateNewMsg (void)
  446. {
  447.     clearcache();
  448.     
  449.     purgetext();    /* Get rid of previous message */
  450.  
  451.     assert(msghead==NULL);
  452. }
  453.  
  454. int DLLFUNC AddLineToMsg (char * line)
  455. {
  456.     struct lltext * cur, * new;
  457.  
  458.     assert(line!=NULL);
  459.     assert(strlen(line)<999);
  460.  
  461.     clearcache();
  462.  
  463.     /* Create new node of text */
  464.     new=(struct lltext * )malloc(sizeof(struct lltext));
  465.     if (new==NULL) return ERRMEM;
  466.     memset(new,0,sizeof(struct lltext));
  467.     new->next=NULL;
  468.     new->text=strdup(line);
  469.     if (new->text==NULL) return ERRMEM;
  470.  
  471.     /* Add to list */
  472.     if (msghead==NULL)
  473.     {
  474.         /* Add at head */
  475.         msghead=new;
  476.     } else
  477.     {
  478.         cur=msghead;
  479.         while (cur->next!=NULL)    /* Find tail */
  480.             cur=cur->next;
  481.         /* Add at tail of list */
  482.         cur->next=new;
  483.     }
  484. }
  485.     
  486.  
  487. int DLLFUNC GetMsg (int areaindex, int msgindex)
  488. {
  489.     struct llareas * area;
  490.     struct llmsg * msg;
  491.     int result;
  492.  
  493.     purgetext();    /* Get rid of previous message */
  494.  
  495.     area=findarea(areaindex);
  496.     msg=findmsg(areaindex,msgindex);
  497.  
  498.     result=loadtext(area,msg);
  499.  
  500.     return result;
  501. }
  502.  
  503. int DLLFUNC GetNumLines (void)
  504. {
  505.     struct lltext * cur;
  506.     int count;
  507.  
  508.     count=0;
  509.     cur=msghead;
  510.     while (cur)
  511.     {
  512.         cur=cur->next;
  513.         count++;
  514.     }
  515.  
  516.     return count;
  517. }
  518.  
  519. char * DLLFUNC GetLine (int line)
  520. {
  521.     int count;
  522.     struct lltext * cur;
  523.  
  524.     assert (line>0);
  525.     assert (line<=GetNumLines());
  526.  
  527.     if (textcache.line==(line-1))    /* Cache hit for next line */
  528.     {
  529.         textcache.line++;
  530.         textcache.curline=textcache.curline->next;
  531.         assert(textcache.curline!=NULL);
  532.  
  533.         return textcache.curline->text;
  534.     }
  535.  
  536.     count=1;
  537.     cur=msghead;
  538.     while (count!=line && cur!=NULL)
  539.     {
  540.         cur=cur->next;
  541.         count++;
  542.     }
  543.  
  544.     assert(cur!=NULL);
  545.     textcache.line=line;
  546.     textcache.curline=cur;
  547.     return cur->text;
  548. }
  549.  
  550. int DLLFUNC GetInfo (void)
  551. {
  552.     FILE * fin;
  553.     char fname[MAXLINE];
  554.     long length;
  555.     int result;
  556.  
  557.     purgetext();    /* Remove old message */
  558.  
  559. /*      sprintf(fname,"%s%s",packetpath,INFOFNAME);     */
  560.     strcpy(fname,packetpath);       /*  "/packetpath/INFOFNAME" */ 
  561.     strcat(fname,INFOFNAME);
  562.  
  563.     /*      Open the file */
  564.     fin=fopen(fname,"rb");  /* MS-DOS likes it binary */
  565.     if (fin==NULL) return 1;
  566.  
  567.     fseek(fin,0,SEEK_END);  /* go to EOF */
  568.     length=ftell(fin);              /* How long is the file ? */
  569.  
  570.     /* Put INFO file into message buffer */
  571.     result=stuffmessage     (fin, 0, length);
  572.  
  573.     fclose(fin);
  574.  
  575.     return result;
  576. }
  577.  
  578. void rot13 (unsigned char * line)
  579. {
  580.     while ((*line)!='\0')
  581.     {
  582.         if (islower(*line))
  583.         {
  584.             (*line)+=13;
  585.             if (*line>'z') (*line)-=26;
  586.         }
  587.         else if (isupper (*line))
  588.         {
  589.             (*line)+=13;
  590.             if (*line>'Z') (*line)-=26;
  591.         }
  592.         line++;
  593.     }
  594. }
  595.  
  596. void DLLFUNC Rot13Msg (void)
  597. {
  598.     int count;
  599.  
  600.     clearcache();
  601.  
  602.     count=1;
  603.     /* Skip headers */
  604.     while (count<=GetNumLines() && strlen(GetLine(count)) >1)
  605.         count++;
  606.     
  607.     while (count<=GetNumLines())
  608.     {
  609.         rot13((unsigned char *)GetLine(count));
  610.         count++;
  611.     }
  612. }
  613.  
  614. char * DLLFUNC GetHeader (char * header)
  615. {
  616.     int count;
  617.     char * line;
  618.     char * value;
  619.  
  620.     assert (header!=NULL);
  621.  
  622.     count=1;
  623.     line=NULL;
  624.     value=NULL;
  625.  
  626.     do
  627.     {       
  628.         line=GetLine(count);
  629.         count++;
  630.         extractvalue (line, header, &value);
  631.     }
  632.     while ( (strlen(line)>1) && value==NULL );
  633.  
  634.     return value;
  635. }
  636.  
  637. int DLLFUNC DeleteMsg (int areaindex, int msgindex)
  638. {
  639.     struct llareas * area;
  640.     struct llmsg * cur;
  641.     FILE * fout, * fin;
  642.     int count;
  643.     long fpos;
  644.     int c;
  645.     int result;
  646.  
  647.     assert (areaindex>0);
  648.     assert (msgindex>0);
  649.     assert (areaindex<=GetNumAreas());
  650.     assert (msgindex<=GetNumMsgs(areaindex));
  651.  
  652.     area=findarea(areaindex);
  653.     assert(area!=NULL);
  654.         
  655.     cur=area->head;
  656.     count=1;
  657.     while ( (count!=msgindex) && (cur!=NULL) )
  658.     {
  659.         cur=cur->next;
  660.         count++;
  661.     }
  662.     assert (cur!=NULL);
  663.     
  664.     /* We copy the file over, up to start, skip length bytes, and finish it off */
  665.     fin=fopen(area->prefix,"rb");
  666.     if (fin==NULL) return ERRIO;
  667.     /* New temporary file */
  668.     fout=fopen("TEMP.FOL","wb");
  669.     if (fout==NULL) return ERRIO;
  670.     
  671.     /* Copy up to the deleted message */
  672.     fpos=0;
  673.     while (fpos<cur->start-4)
  674.     {
  675.         fpos++;
  676.         c=fgetc(fin);
  677.         if (c==EOF) return ERRIO;
  678.         result=fputc(c,fout);
  679.         if (result==EOF) return ERRIO;
  680.     }
  681.     /* Skip the deleted message */
  682.     assert(cur->length>0);
  683.     while (fpos<cur->start+cur->length)
  684.     {
  685.         fpos++;
  686.         c=fgetc(fin);
  687.         if (c==EOF) return ERRIO;
  688.     }
  689.     /* Copy rest of file */
  690.     while (!feof(fin))
  691.     {
  692.         c=fgetc(fin);
  693.         if (c==EOF) break;
  694.         result=fputc(c,fout);
  695.         if (result==EOF) return ERRIO;
  696.     }
  697.     result=fclose(fin);
  698.     if (result==EOF) return ERRIO;
  699.     result=fclose(fout);
  700.     if (result==EOF) return ERRIO;
  701.     
  702.     /* Remove the old folder, and rename the temp one on top */
  703.     result=unlink(area->prefix);
  704.     if (result!=0) return ERRIO;    
  705.     result=rename("TEMP.FOL",area->prefix);
  706.     if (result!=0) return ERRIO;
  707.     
  708.     return 0;
  709. }