home *** CD-ROM | disk | FTP | other *** search
- /* msgs.c -- Handle all sorts of message formats
- This file is part of Paperboy, an offline mail/newsreader for Windows
- Copyright (C) 1994 Michael H. Vartanian
- vart@clark.net
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
- #include <stdio.h>
- #include <string.h>
- #include <time.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include "soup.h"
- #include "error.h"
- #include "areas.h"
- #include "structs.h"
- #include "msgs.h"
- #include "unixmail.h"
- #include "reclaim.h"
-
- extern char * packetpath; /* base directory for files */
-
- struct lltext * msghead=NULL;
-
- struct stextcache
- {
- int line;
- struct lltext * curline;
- } textcache;
-
- int convmonth(char * inmonth)
- {
- int k;
-
- for (k=0; k<=11; k++)
- {
- if (!strcmp(inmonth,months[k])) break;
- }
-
- return k; /* If month not found, returns December? */
- }
-
- void makeidate (struct llmsg * cur)
- /* Convert date string to time_t */
- {
- char * basedate, * freeme;
- time_t idate;
- struct tm hold;
- char month[4];
- int mday=1, year=94, hour=8, min=30, sec=0;
- char * p;
-
- assert (cur!=NULL);
- assert (cur->date!=NULL);
- if (cur->date==NULL)
- {
- cur->idate=0; /* Zulu */
- return;
- }
-
- assert (strlen(cur->date)!=0);
- freeme=strdup(cur->date);
- basedate=freeme;
- /* Skip over blanks, and any day-of-week stuff */
- while (*basedate && !isdigit(*basedate)) basedate++;
-
- p=strtok(basedate," ");
- if (p!=NULL) mday=atoi(p);
- p=strtok(NULL," ");
- if (p!=NULL) strcpy(month,p);
- p=strtok(NULL," ");
- if (p!=NULL) year=atoi(p);
- p=strtok(NULL,":");
- if (p!=NULL) hour=atoi(p);
- p=strtok(NULL,":");
- if (p!=NULL) min =atoi(p);
- p=strtok(NULL,":");
- if (p!=NULL) sec =atoi(p);
-
- if (year>1900) year-=1900;
- hold.tm_mday=mday;
- hold.tm_year=year;
- hold.tm_hour=hour;
- hold.tm_min=min;
- hold.tm_sec=sec;
- hold.tm_wday=0;
- hold.tm_yday=0;
- hold.tm_isdst=0;
- hold.tm_mon=convmonth(month);
-
- idate=mktime(&hold);
- cur->idate=idate;
- cur->thread_idate=idate;
- free (freeme);
- /* printf("\t\tIN:%s\n\t\tOUT:(%d)%s\n",cur->date,idate,ctime(&idate)); */
- }
-
- int getstarts (FILE * fin, struct llareas * area)
- {
- char line[MAXLINE];
- long length;
- struct llmsg * cur;
-
- assert(fin!=NULL);
- assert(area!=NULL);
- assert(area->head==NULL);
-
- rewind(fin);
-
- while (!feof(fin))
- {
- /* Get start and end of message */
- fgetlf(sizeof(line)-1,fin,line);
- if (feof(fin)) break;
- length=atol(&line[strlen(RNEWSHEAD)+1]);
- if (length==0) return ERRPARSE;
- if (length>0) /* valid message */
- {
- /* Add to head of linked list */
- cur=(struct llmsg *)malloc(sizeof(struct llmsg));
- if (cur==NULL) return ERRMEM;
- memset(cur,0,sizeof(struct llmsg)); /* zero it out */
- cur->magic=MSGMAGIC;
- cur->next=area->head;
- area->head=cur;
- cur->start=ftell(fin); /* file pointer is after #! rnews n\n */
- cur->length=length;
- fseek(fin,length,SEEK_CUR); /* Next message */
- }
- }
-
- return 0;
- }
-
-
- int getheaders (FILE * fin, struct llareas * area)
- {
- struct llmsg * cur;
- char line[MAXLINE];
-
- /* Go back and get headers (subject, author, etc. ) */
- cur=area->head; /* First message */
- while (cur!=NULL)
- {
- fseek(fin,cur->start,SEEK_SET); /* go to start of message */
- do
- {
- fgetlf(sizeof(line)-1,fin,line); /* Read a line */
- extractvalue (line,SUBJSTR,&(cur->subject));
- extractvalue (line,FROMSTR,&(cur->author));
- extractvalue (line,DATESTR,&(cur->date));
- }
- while ( ( (!cur->date) || (!cur->author) || (!cur->subject) ) && (*line!='\0') ); /* End of headers */
-
- if (cur->subject==NULL) cur->subject=strdup("Subject Unknown");
- if (strlen(cur->subject)>999) cur->subject[999]='\0';
- if (cur->author==NULL) cur->author=strdup("Author Unknown");
- if (cur->date==NULL) cur->date=strdup("01 Jan 1994 08:00:00 EST");
- makeidate(cur);
- cur=cur->next;
- }
- return 0;
- }
-
- int parsernews (struct llareas * area)
- {
- /* A USENET message file has a header of the form "#! rnews n"
- where n is the number of bytes in the message, following the
- LF character after the header.
- */
- FILE * fin;
- int result;
-
- area->head=NULL; /* No message yet */
-
-
- /* Open the file */
- assert(area->prefix!=NULL);
- fin=fopen(area->prefix,"rb"); /* MS-DOS likes it binary */
- if (fin==NULL) return ERRIO;
-
- result=getstarts(fin,area); /* An index file would definetly have this */
- if (result) return result;
-
- result=getheaders(fin,area); /* An index file might have this */
- if (result) return result;
-
- fclose(fin);
- return 0;
- }
-
-
- int extractvalue (char * line, char * header, char ** result)
- {
- char * value;
- char * newvalue;
- char fullheader[50];
-
- assert (line!=NULL);
- assert (header!=NULL);
- assert (result!=NULL);
-
- strncpy(fullheader,header,45); /* Make foo into foo:_ */
- strcat(fullheader,": ");
-
- /* Searches line for header, placing rest into result */
- if (_strnicmp(line,fullheader,strlen(fullheader))==0) /* Match? */
- {
- value=strchr(line,':')+2; /* Value points to the value after "header: " */
- while (*value==' ') value++; /* Skip leading spaces */
- assert (value!=NULL);
- assert (strlen(value)!=0);
- newvalue=strdup(value);
- assert(newvalue!=NULL);
- if (newvalue==NULL) return ERRMEM;
- *result=newvalue;
- }
-
- return 0;
- }
-
- int parsemsg (struct llareas * area)
- {
- int result;
-
- assert(area!=NULL);
-
- /* If we've already read in messages, skip processing */
- if (area->head!=NULL) return 0;
-
- result=0;
-
- switch (area->encoding[0])
- {
- case RNEWSTYPE:
- {
- result=parsernews (area);
- break;
- }
- case MAILTYPE:
- {
- result=parseunixmail (area);
- break;
- }
- case MAILMMDF:
- {
- result=ERRPARSE;
- break;
- }
- case BINMAIL:
- {
- result=parsebinmail (area);
- break;
- }
- default:
- result=ERRPARSE;
- }
-
- return result;
- }
-
- struct llmsg * findmsg (int areaindex, int msgindex)
- {
- struct llareas * area;
- struct llmsg * cur;
- int count;
-
- assert (areaindex>0);
- assert (msgindex>0);
- assert (areaindex<=GetNumAreas());
- assert (msgindex<=GetNumMsgs(areaindex));
-
- area=findarea(areaindex);
- cur=area->head;
- count=1;
- while ( (count!=msgindex) && (cur!=NULL) )
- {
- cur=cur->next;
- count++;
- }
-
- assert (cur!=NULL);
-
- return cur;
- }
-
-
- char * DLLFUNC GetSubject (int areaindex, int msgindex)
- {
- struct llmsg * cur;
-
- cur=findmsg(areaindex,msgindex);
- return cur->subject;
- }
-
-
- char * DLLFUNC GetAuthor (int areaindex, int msgindex)
- {
- struct llmsg * cur;
-
- cur=findmsg(areaindex,msgindex);
- return cur->author;
- }
-
-
- char * DLLFUNC GetDate (int areaindex, int msgindex)
- {
- struct llmsg * cur;
-
- cur=findmsg(areaindex,msgindex);
- return cur->date;
- }
-
-
- long DLLFUNC GetLength (int areaindex, int msgindex)
- {
- struct llmsg * cur;
-
- cur=findmsg(areaindex,msgindex);
- return cur->length;
- }
-
- int DLLFUNC GetNumMsgs (int index)
- {
- struct llareas * area;
- struct llmsg * cur;
- int count;
-
- assert (index>0);
- assert (index<=GetNumAreas());
-
- area=findarea(index);
- cur=area->head;
-
- count=0;
- while (cur!=NULL)
- {
- cur=cur->next;
- count++;
- }
-
- return count;
- }
-
- void clearcache(void)
- {
- textcache.line=-9;
- textcache.curline=NULL;
- }
-
- void purgetext (void)
- {
- /* Free up old message text */
- struct lltext * next;
-
- clearcache();
-
- while (msghead!=NULL)
- {
- next=msghead->next;
- if (msghead->text!=NULL) free (msghead->text);
- free(msghead);
- msghead=next;
- }
- }
-
-
- int stuffmessage(FILE * fin, long start, long length)
- {
- char line[MAXLINE];
- struct lltext * new, * tail;
- int result;
-
- clearcache();
-
- /* Go to start of message */
- result=fseek(fin,start,SEEK_SET);
- if (result!=0) return ERRIO;
-
- while ( ftell(fin) - start < length )
- {
- /* get next line in message */
- fgetlf(sizeof(line),fin,line);
-
- /* Create new line node */
- new=(struct lltext *)malloc(sizeof(struct lltext));
- if (new==NULL) return ERRMEM;
- memset(new,0,sizeof(struct lltext)); /* Zero it out */
-
- /* add to tail of linked list */
- if (msghead==NULL)
- {
- msghead=new;
- }
- else
- {
- tail->next=new;
- }
- tail=new;
-
- /* Copy message text into beast */
- assert (line!=NULL);
- /* assert (strlen(line)!=0); */
- /* assert (strlen(line)<999); */
- if (strlen(line)>999) line[999]='\0'; /* Truncate line after 999 characters */
- new->text=strdup(line);
- if (new->text==NULL) return ERRMEM;
- }
- return 0;
- }
-
-
- int loadtext (struct llareas * area,struct llmsg * msg)
- {
- FILE * fin;
- int result;
-
- assert(msghead==NULL); /* Previous text should've been purged */
-
- /* Open the file */
- assert(area->prefix!=NULL);
- fin=fopen(area->prefix,"rb"); /* MS-DOS likes it binary */
- if (fin==NULL) return ERRIO;
-
- result=stuffmessage(fin,msg->start,msg->length);
- if (result) return result;
-
- fclose (fin);
-
- return 0;
- }
-
- void DLLFUNC CreateNewMsg (void)
- {
- clearcache();
-
- purgetext(); /* Get rid of previous message */
-
- assert(msghead==NULL);
- }
-
- int DLLFUNC AddLineToMsg (char * line)
- {
- struct lltext * cur, * new;
-
- assert(line!=NULL);
- assert(strlen(line)<999);
-
- clearcache();
-
- /* Create new node of text */
- new=(struct lltext * )malloc(sizeof(struct lltext));
- if (new==NULL) return ERRMEM;
- memset(new,0,sizeof(struct lltext));
- new->next=NULL;
- new->text=strdup(line);
- if (new->text==NULL) return ERRMEM;
-
- /* Add to list */
- if (msghead==NULL)
- {
- /* Add at head */
- msghead=new;
- } else
- {
- cur=msghead;
- while (cur->next!=NULL) /* Find tail */
- cur=cur->next;
- /* Add at tail of list */
- cur->next=new;
- }
- }
-
-
- int DLLFUNC GetMsg (int areaindex, int msgindex)
- {
- struct llareas * area;
- struct llmsg * msg;
- int result;
-
- purgetext(); /* Get rid of previous message */
-
- area=findarea(areaindex);
- msg=findmsg(areaindex,msgindex);
-
- result=loadtext(area,msg);
-
- return result;
- }
-
- int DLLFUNC GetNumLines (void)
- {
- struct lltext * cur;
- int count;
-
- count=0;
- cur=msghead;
- while (cur)
- {
- cur=cur->next;
- count++;
- }
-
- return count;
- }
-
- char * DLLFUNC GetLine (int line)
- {
- int count;
- struct lltext * cur;
-
- assert (line>0);
- assert (line<=GetNumLines());
-
- if (textcache.line==(line-1)) /* Cache hit for next line */
- {
- textcache.line++;
- textcache.curline=textcache.curline->next;
- assert(textcache.curline!=NULL);
-
- return textcache.curline->text;
- }
-
- count=1;
- cur=msghead;
- while (count!=line && cur!=NULL)
- {
- cur=cur->next;
- count++;
- }
-
- assert(cur!=NULL);
- textcache.line=line;
- textcache.curline=cur;
- return cur->text;
- }
-
- int DLLFUNC GetInfo (void)
- {
- FILE * fin;
- char fname[MAXLINE];
- long length;
- int result;
-
- purgetext(); /* Remove old message */
-
- /* sprintf(fname,"%s%s",packetpath,INFOFNAME); */
- strcpy(fname,packetpath); /* "/packetpath/INFOFNAME" */
- strcat(fname,INFOFNAME);
-
- /* Open the file */
- fin=fopen(fname,"rb"); /* MS-DOS likes it binary */
- if (fin==NULL) return 1;
-
- fseek(fin,0,SEEK_END); /* go to EOF */
- length=ftell(fin); /* How long is the file ? */
-
- /* Put INFO file into message buffer */
- result=stuffmessage (fin, 0, length);
-
- fclose(fin);
-
- return result;
- }
-
- void rot13 (unsigned char * line)
- {
- while ((*line)!='\0')
- {
- if (islower(*line))
- {
- (*line)+=13;
- if (*line>'z') (*line)-=26;
- }
- else if (isupper (*line))
- {
- (*line)+=13;
- if (*line>'Z') (*line)-=26;
- }
- line++;
- }
- }
-
- void DLLFUNC Rot13Msg (void)
- {
- int count;
-
- clearcache();
-
- count=1;
- /* Skip headers */
- while (count<=GetNumLines() && strlen(GetLine(count)) >1)
- count++;
-
- while (count<=GetNumLines())
- {
- rot13((unsigned char *)GetLine(count));
- count++;
- }
- }
-
- char * DLLFUNC GetHeader (char * header)
- {
- int count;
- char * line;
- char * value;
-
- assert (header!=NULL);
-
- count=1;
- line=NULL;
- value=NULL;
-
- do
- {
- line=GetLine(count);
- count++;
- extractvalue (line, header, &value);
- }
- while ( (strlen(line)>1) && value==NULL );
-
- return value;
- }
-
- int DLLFUNC DeleteMsg (int areaindex, int msgindex)
- {
- struct llareas * area;
- struct llmsg * cur;
- FILE * fout, * fin;
- int count;
- long fpos;
- int c;
- int result;
-
- assert (areaindex>0);
- assert (msgindex>0);
- assert (areaindex<=GetNumAreas());
- assert (msgindex<=GetNumMsgs(areaindex));
-
- area=findarea(areaindex);
- assert(area!=NULL);
-
- cur=area->head;
- count=1;
- while ( (count!=msgindex) && (cur!=NULL) )
- {
- cur=cur->next;
- count++;
- }
- assert (cur!=NULL);
-
- /* We copy the file over, up to start, skip length bytes, and finish it off */
- fin=fopen(area->prefix,"rb");
- if (fin==NULL) return ERRIO;
- /* New temporary file */
- fout=fopen("TEMP.FOL","wb");
- if (fout==NULL) return ERRIO;
-
- /* Copy up to the deleted message */
- fpos=0;
- while (fpos<cur->start-4)
- {
- fpos++;
- c=fgetc(fin);
- if (c==EOF) return ERRIO;
- result=fputc(c,fout);
- if (result==EOF) return ERRIO;
- }
- /* Skip the deleted message */
- assert(cur->length>0);
- while (fpos<cur->start+cur->length)
- {
- fpos++;
- c=fgetc(fin);
- if (c==EOF) return ERRIO;
- }
- /* Copy rest of file */
- while (!feof(fin))
- {
- c=fgetc(fin);
- if (c==EOF) break;
- result=fputc(c,fout);
- if (result==EOF) return ERRIO;
- }
- result=fclose(fin);
- if (result==EOF) return ERRIO;
- result=fclose(fout);
- if (result==EOF) return ERRIO;
-
- /* Remove the old folder, and rename the temp one on top */
- result=unlink(area->prefix);
- if (result!=0) return ERRIO;
- result=rename("TEMP.FOL",area->prefix);
- if (result!=0) return ERRIO;
-
- return 0;
- }