home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Spezial
/
SPEZIAL2_97.zip
/
SPEZIAL2_97.iso
/
ANWEND
/
ONLINE
/
HYPERMAI
/
HYPERMAI.ZIP
/
parse.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-03-16
|
18KB
|
718 lines
/*
** Copyright (C) 1994, Enterprise Integration Technologies Corp.
** All Rights Reserved.
** Kevin Hughes, kevinh@eit.com
** 7/31/94
*/
#include "hypermail.h"
#include "parse.h"
/* Parsing...the heart of Hypermail!
** This loads in the articles from stdin or a mailbox, adding the right
** field variables to the right structures. If readone is set, it will
** think anything it reads in is one article only.
*/
void loadheaders(mbox, use_stdin, readone)
char *mbox;
int use_stdin;
int readone;
{
FILE *fp;
char name[NAMESTRLEN], email[MAILSTRLEN], date[DATESTRLEN],
msgid[MSGDSTRLEN], subject[SUBJSTRLEN], inreply[REPYSTRLEN],
line[MAXLINE], tmpfrom[MAXLINE], fromdate[DATESTRLEN],
oldline[MAXLINE];
int num, isinheader, hassubject, hasdate, wasinreply;
struct body *bp;
if (!strcmp(mbox, "NONE") || use_stdin)
fp = stdin;
else {
if ((fp = fopen(mbox, "r")) == NULL) {
sprintf(errmsg, "Couldn't open mail archive \"%s\".",
mbox);
progerr(NULL);
}
}
if (readone)
num = bignum;
else
num = 0;
hassubject = 0;
hasdate = 0;
wasinreply = 0;
isinheader = 1;
inreply[0] = '\0';
tmpfrom[0] = '\0';
oldline[0] = '\0';
bp = NULL;
if (!readone) {
replylist = NULL;
subjectlist = NULL;
authorlist = NULL;
datelist = NULL;
}
if (showprogress && readone)
printf("Reading new header...\n");
if (showprogress && !readone) {
if (!strcmp(mbox, "NONE") || use_stdin)
printf("Loading mailbox... ");
else
printf("Loading mailbox \"%s\"... ", mbox);
}
while (fgets(line, MAXLINE, fp) != NULL) {
if (isinheader) {
if (!strncmp(line, "Received:", 9) ||
!strncmp(line, "Return-Path:", 12) ||
!strncmp(line, "Cc:", 3) ||
!strncmp(line, "X-", 2) ||
!strncmp(line, "Flags:", 6))
continue;
if (!strncmp(line, "From ", 5))
strcpy(fromdate, (char *) getfromdate(line));
else if (!strncmp(line, "Date:", 5)) {
bp = (struct body *) addbody(bp, line);
strcpy(date, (char *) getmaildate(line));
hasdate = 1;
}
else if (!strncmp(line, "From:", 5)) {
bp = (struct body *) addbody(bp, line);
getname(line, name, email);
}
else if (!strncmp(line, "Message-Id:", 11)) {
bp = (struct body *) addbody(bp, line);
strcpy(msgid, (char *) getid(line));
}
else if (!strncmp(line, "Subject:", 8)) {
bp = (struct body *) addbody(bp, line);
strcpy(subject, (char *) getsubject(line));
hassubject = 1;
}
else if (!strncmp(line, "In-Reply-To:", 12)) {
bp = (struct body *) addbody(bp, line);
strcpy(inreply, (char *) getreply(line));
wasinreply = 1;
}
else if ((!strncmp(line, " ", 4) ||
line[0] == '\t') &&
strchr(line, '<') && strchr(line, '>') &&
strchr(line, '@') && wasinreply) {
bp = (struct body *) addbody(bp, line);
strcpy(inreply, (char *) getreply(line));
wasinreply = 0;
}
else if (!strncmp(line, "To:", 3))
bp = (struct body *) addbody(bp, line);
else if (line[0] == '\n') {
bp = (struct body *) addbody(bp, line);
isinheader = 0;
}
}
else {
if (!strncmp(line, "From ", 5)) {
if (readone)
continue;
if (strstr(oldline,
"Forwarded message:")) {
oldline[0] = '\0';
continue;
}
isinheader = 1;
wasinreply = 0;
if (!hassubject)
strcpy(subject, NOSUBJECT);
else
hassubject = 1;
if (!hasdate)
strcpy(date, NODATE);
else
hasdate = 1;
if (inreply[0] == '\0')
oneunre(inreply, subject);
while (rmlastlines(bp));
addhash(num, date, name, email, msgid, subject,
inreply, fromdate, bp);
authorlist = (struct header *)
addheader(authorlist, num, name, subject,
date, 1);
subjectlist = (struct header *)
addheader(subjectlist, num, name, unre(subject),
date, 0);
datelist = (struct header *)
addheader(datelist, num, name, subject,
fromdate, 2);
strcpy(fromdate, (char *) getfromdate(line));
bp = NULL;
num++;
if (!(num % 10) && showprogress && !readone) {
printf("\b\b\b\b%4d", num);
fflush(stdout);
}
inreply[0] = '\0';
}
else
bp = (struct body *) addbody(bp, line);
}
strcpy(oldline, line);
}
if (!isinheader) {
if (!hassubject)
strcpy(subject, NOSUBJECT);
if (!hasdate)
strcpy(date, NODATE);
if (inreply[0] == '\0')
oneunre(inreply, subject);
while (rmlastlines(bp));
addhash(num, date, name, email, msgid, subject, inreply,
fromdate, bp);
authorlist = (struct header *)
addheader(authorlist, num, name, subject, date, 1);
subjectlist = (struct header *)
addheader(subjectlist, num, name, unre(subject), date, 0);
datelist = (struct header *) addheader(datelist, num, name,
subject, fromdate, 2);
num++;
}
if (showprogress && !readone)
printf("\b\b\b\b%4d articles.\n", num);
if (!readone)
bignum = num - 1;
fclose(fp);
crossindex();
threadlist = NULL;
printedthreadlist = NULL;
crossindexthread1(datelist);
}
/* All this does is get all the relevant header information from the
** comment fields in existing archive files. Everything is loaded into
** structures in the exact same way as if articles were being read from
** stdin or a mailbox.
*/
void loadoldheaders(dir)
char *dir;
{
FILE *fp;
char name[NAMESTRLEN], email[MAILSTRLEN], date[DATESTRLEN],
msgid[MSGDSTRLEN], subject[SUBJSTRLEN], inreply[REPYSTRLEN],
line[MAXLINE], fromdate[DATESTRLEN], filename[MAXFILELEN];
int num;
struct body *bp;
num = 0;
sprintf(filename, "%s%s%.4d.html", dir,
(dir[strlen(dir) - 1] == '/') ? "" : "/", num);
bp = NULL;
bp = (struct body *) addbody(bp, "\0");
authorlist = subjectlist = datelist = NULL;
if (showprogress)
printf("Reading old headers... ");
while ((fp = fopen(filename, "r")) != NULL) {
fgets(line, MAXLINE, fp);
strcpy(fromdate, (char *) getvalue(line));
fgets(line, MAXLINE, fp);
strcpy(date, (char *) getvalue(line));
fgets(line, MAXLINE, fp);
strcpy(name, (char *) getvalue(line));
fgets(line, MAXLINE, fp);
strcpy(email, (char *) getvalue(line));
fgets(line, MAXLINE, fp);
strcpy(subject, (char *) unconvchars(getvalue(line)));
fgets(line, MAXLINE, fp);
strcpy(msgid, (char *) getvalue(line));
fgets(line, MAXLINE, fp);
strcpy(inreply, (char *) unconvchars(getvalue(line)));
fclose(fp);
addhash(num, date, name, email, msgid, subject,
inreply, fromdate, bp);
authorlist = (struct header *)
addheader(authorlist, num, name, subject, date, 1);
subjectlist = (struct header *)
addheader(subjectlist, num, name, unre(subject), date, 0);
datelist = (struct header *)
addheader(datelist, num, name, subject, fromdate, 2);
num++;
if (!(num % 10) && showprogress) {
printf("\b\b\b\b%4d", num);
fflush(stdout);
}
sprintf(filename, "%s%s%.4d.html", dir,
(dir[strlen(dir) - 1] == '/') ? "" : "/", num);
}
if (showprogress)
printf("\b\b\b\b%4d articles.\n", num);
if (!num)
bignum = 0;
else
bignum = num;
}
/* Adds a "Next:" link in the proper article, after the archive has been
** incrementally updated.
*/
void fixnextheader(dir, num)
char *dir;
int num;
{
char filename[MAXFILELEN], line[MAXLINE], name[NAMESTRLEN],
email[MAILSTRLEN], subject[SUBJSTRLEN], inreply[REPYSTRLEN],
date[DATESTRLEN], fromdate[DATESTRLEN], msgid[MSGDSTRLEN];
struct body *bp, *status;
FILE *fp;
sprintf(filename, "%s%s%.4d.html", dir,
(dir[strlen(dir) - 1] == '/') ? "" : "/", num);
bp = NULL;
if ((fp = fopen(filename, "r")) != NULL) {
while ((fgets(line, MAXLINE, fp)) != NULL)
bp = (struct body *) addbody(bp, line);
}
else
return;
fclose(fp);
if ((fp = fopen(filename, "w+")) != NULL)
while (bp != NULL) {
fprintf(fp, "%s", bp->line);
if (!strncmp(bp->line, "<!-- next=", 10)) {
status = (struct body *) hashnumlookup(num + 1,
name, email, subject, inreply, date, fromdate,
msgid);
if (status != NULL) {
fprintf(fp, "<li> <b>Next message:</b> ");
fprintf(fp,
"<a href=\"%.4d.html\">%s: \"%s\"</a>\n",
num + 1, name, convchars(subject));
}
}
bp = bp->next;
}
fclose(fp);
}
/* Adds a "Reply:" link in the proper article, after the archive has been
** incrementally updated.
*/
void fixreplyheader(dir, num)
char *dir;
int num;
{
int replynum, subjmatch;
char filename[MAXFILELEN], line[MAXLINE], name[NAMESTRLEN],
email[MAILSTRLEN], subject[SUBJSTRLEN], inreply[REPYSTRLEN],
date[DATESTRLEN], fromdate[DATESTRLEN], msgid[MSGDSTRLEN],
name2[NAMESTRLEN], subject2[SUBJSTRLEN];
struct body *bp, *status;
FILE *fp;
status = (struct body *) hashnumlookup(num,
name, email, subject, inreply, date, fromdate, msgid);
if (status == NULL || inreply[0] == '\0')
return;
if (inreply[0] != '\0') {
replynum = hashreplylookup(inreply, name2, subject2,
&subjmatch);
if (replynum == -1)
return;
}
sprintf(filename, "%s%s%.4d.html", dir,
(dir[strlen(dir) - 1] == '/') ? "" : "/", replynum);
bp = NULL;
if ((fp = fopen(filename, "r")) != NULL) {
while ((fgets(line, MAXLINE, fp)) != NULL)
bp = (struct body *) addbody(bp, line);
}
else
return;
fclose(fp);
if ((fp = fopen(filename, "w+")) != NULL)
while (bp != NULL) {
if (!strncmp(bp->line, "<!-- reply", 10)) {
fprintf(fp, "<li> <b>Reply:</b> ");
fprintf(fp, "<a href=\"%.4d.html\">", num);
fprintf(fp, "%s: \"%s\"</a>\n",
name, convchars(subject));
}
fprintf(fp, "%s", bp->line);
bp = bp->next;
}
fclose(fp);
}
/* Adds a "Next in thread:" link in the proper article, after the archive
** has been incrementally updated.
*/
void fixthreadheader(dir, num)
char *dir;
int num;
{
int threadnum;
char filename[MAXFILELEN], line[MAXLINE], name[NAMESTRLEN],
subject[SUBJSTRLEN];
struct body *bp;
struct reply *rp;
FILE *fp;
for (rp = threadlist; rp != NULL; rp = rp->next)
if (rp->next != NULL && rp->next->msgnum == num &&
rp->msgnum != -1) {
threadnum = rp->msgnum;
strcpy(name, rp->next->name);
strcpy(subject, rp->next->subject);
break;
}
if (rp == NULL)
return;
sprintf(filename, "%s%s%.4d.html", dir,
(dir[strlen(dir) - 1] == '/') ? "" : "/", threadnum);
bp = NULL;
if ((fp = fopen(filename, "r")) != NULL) {
while ((fgets(line, MAXLINE, fp)) != NULL)
bp = (struct body *) addbody(bp, line);
}
else
return;
fclose(fp);
if ((fp = fopen(filename, "w+")) != NULL)
while (bp != NULL) {
fprintf(fp, "%s", bp->line);
if (!strncmp(bp->line, "<!-- nextthr", 12)) {
fprintf(fp, "<li> <b>Next in thread:</b> ");
fprintf(fp, "<a href=\"%.4d.html\">", num);
fprintf(fp, "%s: \"%s\"</a>\n",
name, convchars(subject));
}
bp = bp->next;
}
fclose(fp);
}
/* Cross-indexes - adds to a list of replies. If a message is a reply to
** another, the number of the messge it's replying to is added to the list.
** This list is searched upon printing.
*/
void crossindex()
{
int num, status, maybereply;
char name[NAMESTRLEN], subject[SUBJSTRLEN], email[MAILSTRLEN],
inreply[REPYSTRLEN], date[DATESTRLEN], fromdate[DATESTRLEN],
msgid[MSGDSTRLEN];
num = 0;
replylist = NULL;
while (hashnumlookup(num, name, email, subject, inreply,
date, fromdate, msgid) != NULL) {
if (inreply[0] != '\0') {
status = hashreplynumlookup(inreply, &maybereply);
if (status != -1)
replylist = (struct reply *)
addreply(replylist, status, num, name, subject,
maybereply);
}
num++;
}
}
/* First, print out the threads in order by date...
** Each message number is appended to a thread list. Threads and individual
** messages are separated by a -1.
*/
void crossindexthread1(hp)
struct header *hp;
{
int hasreply;
struct reply *rp;
if (hp != NULL) {
crossindexthread1(hp->left);
for (hasreply = 0, rp = replylist; rp != NULL; rp = rp->next)
if (rp->frommsgnum == hp->msgnum) {
hasreply = 1;
break;
}
if (!hasreply && !wasprinted(printedthreadlist, hp->msgnum)) {
threadlist = (struct reply *)
addreply(threadlist, hp->msgnum, hp->msgnum,
hp->name, hp->subject, 0);
crossindexthread2(hp->msgnum);
threadlist = (struct reply *)
addreply(threadlist, -1, -1, " ", " ", 0);
}
crossindexthread1(hp->right);
}
}
/* Recursively checks for replies to replies to a message, etc.
** Replies are added to the thread list.
*/
void crossindexthread2(num)
int num;
{
struct reply *rp;
for (rp = replylist; rp != NULL; rp = rp->next)
if (rp->msgnum == num) {
threadlist = (struct reply *)
addreply(threadlist, rp->frommsgnum, num,
rp->name, rp->subject, 0);
printedlist = (struct printed *)
markasprinted(printedthreadlist, rp->frommsgnum);
crossindexthread2(rp->frommsgnum);
}
}
/* Grabs the date string from a Date: header.
*/
char *getmaildate(line)
char *line;
{
int i;
char *c;
static char date[DATESTRLEN];
c = (char *) strchr(line, ':');
if ((*(c + 1) && *(c + 1) == '\n') ||
(*(c + 2) && *(c + 2) == '\n')) {
strcpy(date, NODATE);
return date;
}
c += 2;
while (isspace(*c))
c++;
for (i = 0; *c && *c != '\n' && i < DATESTRLEN; c++)
date[i++] = *c;
date[i] = '\0';
return date;
}
/* Grabs the date string from a From article separator.
*/
char *getfromdate(line)
char *line;
{
int i;
char *c;
static char tmpdate[DATESTRLEN];
for (i = 0; days[i] != NULL && (c = (char *) strstr(line, days[i]))
== NULL; i++)
;
if (days[i] == NULL)
tmpdate[0] = '\0';
else {
for (i = 0; *c && *c != '\n' && i < DATESTRLEN; c++)
tmpdate[i++] = *c;
tmpdate[i] = '\0';
if (tmpdate[16] != ':') {
tmpdate[16] = ':';
tmpdate[17] = '0';
tmpdate[18] = '0';
tmpdate[19] = ' ';
tmpdate[20] = thisyear[0];
tmpdate[21] = thisyear[1];
tmpdate[22] = thisyear[2];
tmpdate[23] = thisyear[3];
tmpdate[24] = '\0';
}
sprintf(tmpdate, "%s %s", tmpdate, timezonestr);
return tmpdate;
}
return tmpdate;
}
/* Grabs the name and email address from a From: header.
** This could get tricky; I've tried to keep it simple.
*/
void getname(line, name, email)
char *line;
char *name;
char *email;
{
int i;
char *c;
if ((c = (char *) strchr(line, '@')) == NULL) {
if (strchr(line, '(')) {
c = (char *) strchr(line, ':') + 1;
while (isspace(*c))
c++;
for (i = 0; *c && *c != '(' && *c != ' ' &&
*c != '\n' && i < MAILSTRLEN; c++)
email[i++] = *c;
email[i] = '\0';
}
else
strcpy(email, NOEMAIL);
}
else {
while (*c != ' ' && *c != '<')
c--;
c++;
for (i = 0; *c && *c != '>' && *c != ' ' && *c != '\n' &&
i < MAILSTRLEN;
c++)
email[i++] = *c;
email[i] = '\0';
}
if (strchr(line, '<')) {
c = (char *) strchr(line, ':') + 1;
while (isspace(*c) || *c == '\"')
c++;
}
else if (strchr(line, '('))
c = (char *) strchr(line, '(') + 1;
else {
if (strcmp(email, NOEMAIL))
strcpy(name, email);
else
strcpy(name, NONAME);
return;
}
for (i = 0; *c && *c != '<' && *c != '\"' && *c != ')' &&
*c != '(' && *c != '\n' && i < NAMESTRLEN; c++)
name[i++] = *c;
if (*c == '<' || *c == '(')
name[--i] = '\0';
else
name[i] = '\0';
}
/* Grabs the message ID, like <...> from the Message-ID: header.
*/
char *getid(line)
char *line;
{
int i;
char *c;
static char msgid[MSGDSTRLEN];
c = (char *) strchr(line, '<') + 1;
for (i = 0; *c && *c != '>' && *c != '\n' && i < MSGDSTRLEN; c++) {
if (*c == '\\')
continue;
msgid[i++] = *c;
}
msgid[i] = '\0';
return msgid;
}
/* Grabs the subject from the Subject: header.
*/
char *getsubject(line)
char *line;
{
int i;
char *c;
static char subject[SUBJSTRLEN];
c = (char *) strchr(line, ':') + 2;
while (isspace(*c))
c++;
for (i = 0; *c && *c != '\n' && i < SUBJSTRLEN; c++)
subject[i++] = *c;
subject[i] = '\0';
for (i--; i >= 0 && isspace(subject[i]); i--)
subject[i] = '\0';
if (subject[0] == NULL || isspace(subject[0]) || subject[0] == '\n' ||
!stricmp(subject, "Re:"))
strcpy(subject, NOSUBJECT);
return subject;
}
/* Grabs the message ID, or date, from the In-reply-to: header.
** Who knows what other formats are out there...
*/
char *getreply(line)
char *line;
{
int i;
char *c;
static char reply[REPYSTRLEN];
if ((c = (char *) strstr(line, "dated: ")) != NULL) {
c += 7;
for (i = 0; *c && *c != '.' && *c != '\n' && i < REPYSTRLEN;
c++)
reply[i++] = *c;
reply[i] = '\0';
return reply;
}
if ((c = (char *) strchr(line, '<')) != NULL ) {
c++;
for (i = 0; *c && *c != '>' && *c != '\n' && i < MSGDSTRLEN;
c++) {
if (*c == '\\')
continue;
reply[i++] = *c;
}
reply[i] = '\0';
return reply;
}
if ((c = (char *) strstr(line, "sage of ")) != NULL) {
c += 8;
if (*c == '\"')
c++;
for (i = 0; *c && *c != '.' && *c != '\n' && *c != 'f' &&
i < REPYSTRLEN; c++)
reply[i++] = *c;
reply[i] = '\0';
if (*c == 'f')
reply[--i] = '\0';
return reply;
}
reply[0] = '\0';
return reply;
}