/*
 * This file is part of the FEddi package
 *
 * Personal use allowed under the terms of the
 *
 *              GNU GENERAL PUBLIC LICENSE Version 2
 *              (see LICENSE for the complete text)
 *
 *-------------------------------------------------------------------
 *
 *    ENTER AT YOUR OWN RISK !!
 *
 * This source is without any documentation and can drive you mad.
 * In case of sudden epileptic seizures please call your doctor.
 *
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "regex.h"
#include <ctype.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "inout.h"
#include "proc.h"
#include "structs.h"
#include "template.h"
#include "flags.h"

const char _QUOTE[40]="([[:space:]]*([A-Za-z]*)>+)+";
struct re_pattern_buffer _QUOTE_regexp;
int _QUOTE_on=0;

void outputMsg(FILE *f, int num, char *area,
		MsgHdrType *hdr, int textl, LineListType **text,
		int kludgel, LineListType **kludges)
{
	int i;
	char line[50];
	fprintf(f,"###MESSAGE_START###[%s][%u]\n",area,num);
	if (hdr)
	{
		fputs("##HEADER##\n",f);
		fprintf(f,"#Number: %u\n",num);
		fprintf(f,"#Area: %s\n",area);
		fprintf(f,"#From: %s\n",hdr->WhoFrom);
		fprintf(f,"#@From: %u:%u/%u.%u\n",
				hdr->OrigZone,hdr->OrigNet,hdr->OrigNode,hdr->OrigPoint);
		fprintf(f,"#To: %s\n",hdr->WhoTo);
		fprintf(f,"#@To: %u:%u/%u.%u\n",
				hdr->DestZone,hdr->DestNet,hdr->DestNode,hdr->DestPoint);
		fprintf(f,"#Subject: %s\n",hdr->Subj);
		fprintf(f,"#Date: %s\n",hdr->DateTime);
		if (hdr->Recvdt[0])
			fprintf(f,"#Received: %s\n",hdr->Recvdt);
		for (line[0]=0, i=0; i<16; i++)
			if (hdr->Attribute&(1<<i))
			{
				strcat(line,NAMEFLAG[i]);
				strcat(line," ");
			}
		fprintf(f,"#Attribute: %s\n",line);
		line[0]=0;
		if (hdr->Personal) strcat(line,"prs ");
		if (hdr->Marked) strcat(line,"mrk ");
		if (hdr->Protected) strcat(line,"prt ");
		if (hdr->Deleted) strcat(line,"del ");
		if (hdr->New) strcat(line,"new ");
		if (hdr->NewPersonal) strcat(line,"nwp ");
		if (hdr->TruncSent) strcat(line,"trs ");
		if (hdr->DeleteSent) strcat(line,"dls ");
		if (hdr->Direct) strcat(line,"dir ");
		fprintf(f,"#Flags: %s\n",line);
		fprintf(f,"#Size: %u\n",hdr->NumRecs*256+MsgHdrSize);
	}
	if (text && textl)
	{
		fputs("##TEXT##\n",f);
		for (i=0; i<textl; i++)
		{
			fputs((*text)[i].line,f);
			if ((*text)[i].CR)
				fputc('\n',f);
			else
				if ((*text)[i].line[strlen((*text)[i].line)-1]!=32)
					fputc(' ',f);
		}
		if (!(*text)[textl-1].CR) fputc('\n',f);
	}
	if (kludges && kludgel)
	{
		fputs("##KLUDGES##\n",f);
		for (i=0; i<kludgel; i++)
			fprintf(f,"%s\n",(*kludges)[i].line);
	}
	fputs("###MESSAGE_END###\n",f);
}

int inputMsg(FILE *f, int COLS, int *save, char *area,
		MsgHdrType *hdr,
		int *lines, LineListType **text,
		int *klines, LineListType **kludges,
		int *slines, LineListType **status)
{
	int mode=-1, i;
	char line[4096], *d1, d;
	Addr4dType addr;
	(*save)=0;
	while (fgets(line,4096,f))
	{
		if ((d1=strchr(line,'\r'))) *d1=0;
		if ((d1=strchr(line,'\n'))) *d1=0;
		if (strncmp(line,"###STATUS_START###",18)==0)
		{
			mode=-2;
			if (status)
			{
				for (i=0; i<*slines; i++)
					free((*status)[i].line);
				free((*status));
				(*status)=NULL;
				*slines=0;
			}
			continue;
		}
		if (strncmp(line,"###MESSAGE_START###",19)==0)
		{
			mode=0;
			continue;
		}
		if (strcmp(line,"##SAVE_MESSAGE_TO_BASE##")==0 && mode>=0)
		{
			(*save)=1;
			continue;
		}
		if (strcmp(line,"##HEADER##")==0 && mode>=0)
		{
			mode=1;
			if (hdr)
				hdr->Attribute=(strcmp(area,"NETMAIL")==0)?
						(StandardFlags|1):StandardFlags;
			continue;
		}
		if (strcmp(line,"##TEXT##")==0 && mode>=0)
		{
			mode=2;
			if (text)
			{
				for (i=0; i<*lines; i++)
					free((*text)[i].line);
				free((*text));
				(*text)=NULL;
				*lines=0;
			}
			continue;
		}
		if (strcmp(line,"##KLUDGES##")==0 && mode>=0)
		{
			mode=3;
			if (kludges)
			{
				for (i=0; i<*klines; i++)
					free((*kludges)[i].line);
				free((*kludges));
				(*kludges)=NULL;
				*klines=0;
			}
			continue;
		}
		if (strcmp(line,"###MESSAGE_END###")==0 && mode>=0)
		{
			mode=-1;
			continue;
		}
		if (strcmp(line,"###STATUS_END###")==0 && mode==-2)
		{
			mode=-1;
			continue;
		}
		if (mode==-2 && status)
		{
			(*slines)++;
			(*status)=(LineListType *)realloc((*status),*slines*LineListSize);
			(*status)[*slines-1].line=(char *)malloc(strlen(line)+1);
			strcpy((*status)[*slines-1].line,line);
			(*status)[*slines-1].CR=(d1!=NULL);
			(*status)[*slines-1].Quote=IsQuote(line);
			(*status)[*slines-1].CutOrigin=0;
			continue;
		}
		if (mode==1 && hdr)
		{
			if (strncmp(line,"#Area: ",7)==0)
			{
				strcpy(area,line+7);
				continue;
			}
			if (strncmp(line,"#From: ",7)==0)
			{
				line[42]=0;
				strcpy(hdr->WhoFrom,line+7);
				continue;
			}
			if (strncmp(line,"#@From: ",8)==0)
			{
				Str2Addr(line+8,&addr);
				hdr->OrigZone=addr.Zone;
				hdr->OrigNet=addr.Net;
				hdr->OrigNode=addr.Node;
				hdr->OrigPoint=addr.Point;
				continue;
			}
			if (strncmp(line,"#To: ",5)==0)
			{
				line[40]=0;
				strcpy(hdr->WhoTo,line+5);
				continue;
			}
			if (strncmp(line,"#@To: ",6)==0)
			{
				Str2Addr(line+6,&addr);
				hdr->DestZone=addr.Zone;
				hdr->DestNet=addr.Net;
				hdr->DestNode=addr.Node;
				hdr->DestPoint=addr.Point;
				continue;
			}
			if (strncmp(line,"#Subject: ",10)==0)
			{
				line[81]=0;
				strcpy(hdr->Subj,line+10);
				continue;
			}
			if (strncmp(line,"#Date: ",7)==0)
			{
				strncpy(hdr->DateTime,line+7,20);
				hdr->DateTime[19]=0;
				continue;
			}
			if (strncmp(line,"#Received: ",11)==0)
			{
				strncpy(hdr->Recvdt,line+11,20);
				hdr->Recvdt[19]=0;
				continue;
			}
			if (strncmp(line,"#Attribute: ",12)==0)
			{
				hdr->Attribute=0;
				for (d1=line+12; *d1; d1+=2)
				{
					while (!isalpha(*d1) && *d1!=0) d1++;
					for (i=0; i<16; i++)
						if (strncasecmp(d1,NAMEFLAG[i],2)==0)
						{
							hdr->Attribute|=(1<<i);
							break;
						}
				}
				continue;
			}
			if (strncmp(line,"#Flags: ",8)==0)
			{
				d1=line+8;
				while (*d1)
				{
#define flagtest(s,f) {if (strncasecmp(d1,s,3)==0) {d1+=3;f=1;while (!isalpha(*d1) && *d1!=0) d1++;}}
					flagtest("prs",hdr->Personal);
					flagtest("mrk",hdr->Marked);
					flagtest("prt",hdr->Protected);
					flagtest("del",hdr->Deleted);
					flagtest("new",hdr->New);
					flagtest("nwp",hdr->NewPersonal);
					flagtest("trs",hdr->TruncSent);
					flagtest("dls",hdr->DeleteSent);
					flagtest("dir",hdr->Direct);
#undef flagtest(s,f)
				}
				continue;
			}
			continue;
		}
		if (mode==2 && text)
		{
			while (strlen(line)>COLS-2)
			{
				for (i=COLS-2; i>0 && !strloc(line[i]," -,"); i--);
				if (i==0)
					i=COLS-1;
				else
					i++;
				d=line[i];
				line[i]=0;
				(*lines)++;
				(*text)=(LineListType *)realloc((*text),*lines*LineListSize);
				(*text)[*lines-1].line=(char *)malloc(strlen(line)+1);
				strcpy((*text)[*lines-1].line,line);
				(*text)[*lines-1].CR=0;
				(*text)[*lines-1].Quote=0;
				if (strncmp((*text)[*lines-1].line,"--- ",4)==0 ||
						strcmp((*text)[*lines-1].line,"---")==0)
					(*text)[*lines-1].CutOrigin=1;
				else
				{
					if (strncmp((*text)[*lines-1].line," * Origin:",10)==0)
						(*text)[*lines-1].CutOrigin=2;
					else
						(*text)[*lines-1].CutOrigin=0;
				}
				line[i]=d;
				memmove(line,line+i,strlen(line)-i+1);
			}
			(*lines)++;
			(*text)=(LineListType *)realloc((*text),*lines*LineListSize);
			(*text)[*lines-1].line=(char *)malloc(strlen(line)+1);
			strcpy((*text)[*lines-1].line,line);
			(*text)[*lines-1].CR=(d1!=NULL);
			(*text)[*lines-1].Quote=IsQuote(line);
			if (strncmp((*text)[*lines-1].line,"--- ",4)==0 ||
					strcmp((*text)[*lines-1].line,"---")==0)
				(*text)[*lines-1].CutOrigin=1;
			else
			{
				if (strncmp((*text)[*lines-1].line," * Origin:",10)==0)
					(*text)[*lines-1].CutOrigin=2;
				else
					(*text)[*lines-1].CutOrigin=0;
			}
			continue;
		}
		if (mode==3 && kludges)
		{
			(*klines)++;
			(*kludges)=(LineListType *)realloc((*kludges),*klines*LineListSize);
			(*kludges)[*klines-1].line=(char *)malloc(strlen(line)+1);
			strcpy((*kludges)[*klines-1].line,line);
			(*kludges)[*klines-1].CR=(d1!=NULL);
			(*kludges)[*klines-1].Quote=IsQuote(line);
			(*kludges)[*klines-1].CutOrigin=0;
			continue;
		}
	}
	return 0;
}

int pipeMsg(int pid, FILE *rp, FILE *wp,
		int num, int COLS, int *save, char *area,
		MsgHdrType *hdr, int *textl, LineListType **text,
		int *kludgel, LineListType **kludges,
		int *statl, LineListType **status)
{
	int ln=0, canr=-1, canw=2, nln=0, nkl=0, i;
	char line[4096], *d1, d;
	LineListType *ntxt=NULL, *nklu=NULL;
	Addr4dType addr;
	fprintf(wp,"###MESSAGE_START###[%s][%u]\n",area,num);
	if (hdr)
	{
		fputs("##HEADER##\n",wp);
		fprintf(wp,"#Number: %u\n",num);
		fprintf(wp,"#Area: %s\n",area);
		fprintf(wp,"#From: %s\n",hdr->WhoFrom);
		fprintf(wp,"#@From: %u:%u/%u.%u\n",
				hdr->OrigZone,hdr->OrigNet,hdr->OrigNode,hdr->OrigPoint);
		fprintf(wp,"#To: %s\n",hdr->WhoTo);
		fprintf(wp,"#@To: %u:%u/%u.%u\n",
				hdr->DestZone,hdr->DestNet,hdr->DestNode,hdr->DestPoint);
		fprintf(wp,"#Subject: %s\n",hdr->Subj);
		fprintf(wp,"#Date: %s\n",hdr->DateTime);
		if (hdr->Recvdt[0])
			fprintf(wp,"#Received: %s\n",hdr->Recvdt);
		for (line[0]=0, i=0; i<16; i++)
			if (hdr->Attribute&(1<<i))
			{
				strcat(line,NAMEFLAG[i]);
				strcat(line," ");
			}
		fprintf(wp,"#Attribute: %s\n",line);
		line[0]=0;
		if (hdr->Personal) strcat(line,"prs ");
		if (hdr->Marked) strcat(line,"mrk ");
		if (hdr->Protected) strcat(line,"prt ");
		if (hdr->Deleted) strcat(line,"del ");
		if (hdr->New) strcat(line,"new ");
		if (hdr->NewPersonal) strcat(line,"nwp ");
		if (hdr->TruncSent) strcat(line,"trs ");
		if (hdr->DeleteSent) strcat(line,"dls ");
		if (hdr->Direct) strcat(line,"dir ");
		fprintf(wp,"#Flags: %s\n",line);
		fprintf(wp,"#Size: %u\n",hdr->NumRecs*256+MsgHdrSize);
	}
	if (text && textl)
		fputs("##TEXT##\n",wp);
	else
	{
		if (kludges && kludgel)
		{
			fputs("##KLUDGES##\n",wp);
			canw=1;
		} else
		{
			fputs("###MESSAGE_END###\n",wp);
			fclose(wp);
			canw=0;
		}
	}
	while (canr || canw)
	{
		if (canr)
			while (canr && canread(rp))
				if (fgets(line,4096,rp))
				{
					if ((d1=strchr(line,'\r'))) *d1=0;
					if ((d1=strchr(line,'\n'))) *d1=0;
					if (strcmp(line,"###STATUS_START###")==0 && canr==-1)
					{
						canr=-2;
						if (status)
						{
							for (i=0; i<(*statl); i++) free((*status)[i].line);
							free((*status));
							(*status)=NULL;
							(*statl)=0;
						}
						continue;
					}
					if (strncmp(line,"###MESSAGE_START###",19)==0 && canr==-1)
					{
						canr=4;
						continue;
					}
					if (strcmp(line,"##SAVE_MESSAGE_TO_BASE##")==0 && canr>=0)
					{
						(*save)=1;
						continue;
					}
					if (strcmp(line,"##HEADER##")==0 && canr>=0)
					{
						canr=3;
						if (hdr)
							hdr->Attribute=(strcmp(area,"NETMAIL")==0)?
									(StandardFlags|1):StandardFlags;
						continue;
					}
					if (strcmp(line,"##TEXT##")==0 && canr>=0)
					{
						canr=2;
						continue;
					}
					if (strcmp(line,"##KLUDGES##")==0 && canr>=0)
					{
						canr=1;
						continue;
					}
					if (strcmp(line,"###MESSAGE_END###")==0 && canr>=0)
					{
						canr=-1;
						continue;
					}
					if (strcmp(line,"###STATUS_END###")==0 && canr==-2)
					{
						canr=-1;
						continue;
					}
					if (canr==3 && hdr)
					{
						if (strncmp(line,"#Area: ",7)==0)
						{
							strcpy(area,line+7);
							continue;
						}
						if (strncmp(line,"#From: ",7)==0)
						{
							line[42]=0;
							strcpy(hdr->WhoFrom,line+7);
							continue;
						}
						if (strncmp(line,"#@From: ",8)==0)
						{
							Str2Addr(line+8,&addr);
							hdr->OrigZone=addr.Zone;
							hdr->OrigNet=addr.Net;
							hdr->OrigNode=addr.Node;
							hdr->OrigPoint=addr.Point;
							continue;
						}
						if (strncmp(line,"#To: ",5)==0)
						{
							line[40]=0;
							strcpy(hdr->WhoTo,line+5);
							continue;
						}
						if (strncmp(line,"#@To: ",6)==0)
						{
							Str2Addr(line+6,&addr);
							hdr->DestZone=addr.Zone;
							hdr->DestNet=addr.Net;
							hdr->DestNode=addr.Node;
							hdr->DestPoint=addr.Point;
							continue;
						}
						if (strncmp(line,"#Subject: ",10)==0)
						{
							line[81]=0;
							strcpy(hdr->Subj,line+10);
							continue;
						}
						if (strncmp(line,"#Date: ",7)==0)
						{
							strncpy(hdr->DateTime,line+7,20);
							hdr->DateTime[19]=0;
							continue;
						}
						if (strncmp(line,"#Received: ",11)==0)
						{
							strncpy(hdr->Recvdt,line+11,20);
							hdr->Recvdt[19]=0;
							continue;
						}
						if (strncmp(line,"#Attribute: ",12)==0)
						{
							hdr->Attribute=0;
							for (d1=line+12; *d1; d1+=2)
							{
								while (!isalpha(*d1) && *d1!=0) d1++;
								for (i=0; i<16; i++)
									if (strncasecmp(d1,NAMEFLAG[i],2)==0)
									{
										hdr->Attribute|=(1<<i);
										break;
									}
							}
							continue;
						}
						if (strncmp(line,"#Flags: ",8)==0)
						{
							d1=line+8;
							while (*d1)
							{
			#define flagtest(s,f) {if (strncasecmp(d1,s,3)==0) {d1+=3;f=1;while (!isalpha(*d1) && *d1!=0) d1++;}}
								flagtest("prs",hdr->Personal);
								flagtest("mrk",hdr->Marked);
								flagtest("prt",hdr->Protected);
								flagtest("del",hdr->Deleted);
								flagtest("new",hdr->New);
								flagtest("nwp",hdr->NewPersonal);
								flagtest("trs",hdr->TruncSent);
								flagtest("dls",hdr->DeleteSent);
								flagtest("dir",hdr->Direct);
			#undef flagtest(s,f)
							}
							continue;
						}
						continue;
					}
					if (canr==2 && text)
					{
						while (strlen(line)>COLS-2)
						{
							for (i=COLS-2; i>0 && !strloc(line[i]," -,"); i--);
							if (i==0)
								i=COLS-1;
							else
								i++;
							d=line[i];
							line[i]=0;
							nln++;
							ntxt=(LineListType *)realloc(ntxt,nln*LineListSize);
							ntxt[nln-1].line=(char *)malloc(strlen(line)+1);
							strcpy(ntxt[nln-1].line,line);
							ntxt[nln-1].CR=0;
							ntxt[nln-1].Quote=0;
							if (strncmp(ntxt[nln-1].line,"--- ",4)==0 ||
									strcmp(ntxt[nln-1].line,"---")==0)
								ntxt[nln-1].CutOrigin=1;
							else
							{
								if (strncmp(ntxt[nln-1].line," * Origin:",10)==0)
									ntxt[nln-1].CutOrigin=2;
								else
									ntxt[nln-1].CutOrigin=0;
							}
							line[i]=d;
							memmove(line,line+i,strlen(line)-i+1);
						}
						nln++;
						ntxt=(LineListType *)realloc(ntxt,nln*LineListSize);
						ntxt[nln-1].line=(char *)malloc(strlen(line)+1);
						strcpy(ntxt[nln-1].line,line);
						ntxt[nln-1].CR=1;
						ntxt[nln-1].Quote=IsQuote(line);
						if (strncmp(ntxt[nln-1].line,"--- ",4)==0 ||
								strcmp(ntxt[nln-1].line,"---")==0)
							ntxt[nln-1].CutOrigin=1;
						else
						{
							if (strncmp(ntxt[nln-1].line," * Origin:",10)==0)
								ntxt[nln-1].CutOrigin=2;
							else
								ntxt[nln-1].CutOrigin=0;
						}
						continue;
					}
					if (canr==1 && kludges)
					{
						nkl++;
						nklu=(LineListType *)realloc(nklu,nkl*LineListSize);
						nklu[nkl-1].line=(char *)malloc(strlen(line)+1);
						strcpy(nklu[nkl-1].line,line);
						nklu[nkl-1].CR=1;
						nklu[nkl-1].Quote=IsQuote(line);
						nklu[nkl-1].CutOrigin=0;
						continue;
					}
					if (canr==-2 && status)
					{
						(*statl)++;
						(*status)=(LineListType *)realloc((*status),(*statl)*LineListSize);
						(*status)[(*statl)-1].line=(char *)malloc(strlen(line)+1);
						strcpy((*status)[(*statl)-1].line,line);
						(*status)[(*statl)-1].CR=1;
						(*status)[(*statl)-1].Quote=0;
						(*status)[(*statl)-1].CutOrigin=0;
						continue;
					}
				} else
				{
					canr=0;
					fclose(rp);
				}
		if (canw && canwrite(wp))
			switch (canw)
			{
				case 2:
					if (ln<*textl)
					{
						fputs((*text)[ln].line,wp);
						if ((*text)[ln].CR)
							fputc('\n',wp);
						else
							if ((*text)[ln].line[strlen((*text)[ln].line)-1]!=32)
								fputc(' ',wp);
						ln++;
					} else
					{
						if (!(*text)[*textl-1].CR) fputc('\n',wp);
						if (kludges && kludgel)
						{
							fputs("##KLUDGES##\n",wp);
							canw=1;
							ln=0;
						} else
						{
							fputs("###MESSAGE_END###\n",wp);
							fclose(wp);
							canw=0;
						}
					}
					break;
				case 1:
					if (ln<*kludgel)
						fprintf(wp,"%s\n",(*kludges)[ln++].line);
					else
					{
						fputs("###MESSAGE_END###\n",wp);
						fclose(wp);
						canw=0;
					}
					break;
			}
	}
	while (waitpid(pid,&i,WNOHANG)!=pid);
	if (text && ntxt)
	{
		for (i=0; i<*textl; i++) free((*text)[i].line);
		free((*text));
		(*text)=ntxt;
		(*textl)=nln;
	}
	if (kludges && nklu)
	{
		for (i=0; i<*kludgel; i++) free((*kludges)[i].line);
		free((*kludges));
		(*kludges)=nklu;
		(*kludgel)=nkl;
	}
	return 1;
}

void loadTextOfMsg(int MAXCOLS, MsgHdrType *mh,
		int *MsgLines, LineListType **MsgTxt,
		int *KludgeLines, LineListType **Kludges,
		int *DispKludgeLines, LineListType **DispKludges)
{
	char line[400], kline[4096], newline[4096];
	char *buffer, *fquote=NULL, *nquote=NULL;
	int j, l=0, n, d, Umbruch, seenby=0, kludge;
	int p, ps, pp, qlvl=0;
	if ((*MsgTxt))
		for (j=0; j<(*MsgLines); j++) free((*MsgTxt)[j].line);
	free((*MsgTxt));
	if ((*Kludges))
		for (j=0; j<(*KludgeLines); j++) free((*Kludges)[j].line);
	free((*Kludges));
	if ((*DispKludges))
		for (j=0; j<(*DispKludgeLines); j++) free((*DispKludges)[j].line);
	free((*DispKludges));
	(*MsgTxt)=(*Kludges)=(*DispKludges)=NULL;
	(*MsgLines)=(*KludgeLines)=(*DispKludgeLines)=0;
	strcpy(kline,"");
	fseek(mtf,mh->StartRec*256,SEEK_SET);
	buffer=(char *)malloc(mh->NumRecs*256);
	fread(buffer,256,mh->NumRecs,mtf);
	n=kludge=0;
	for (j=0; j<(256*mh->NumRecs);)
	{
		if (l==8)
			seenby=(strncasecmp(line,"SEEN-BY:",8)==0);
		if (buffer[j]!=0xd && buffer[j]!=0 && 
				(((seenby || line[0]==1 || kludge) && n<79) ||
				((!seenby && line[0]!=1 && !kludge) &&
				n<MAXCOLS-(fquote?strlen(fquote):0))))
		{
			line[l]=buffer[j];
			l++;
			n++;
			j++;
		} else
		{
			if (n==MAXCOLS && line[0]!=1 && !seenby)
			{
				for (d=0; d<l && !strloc(line[l-d-1]," -,"); d++);
				if (d!=l)
				{
					j-=d;
					l-=d;
					if (line[l-1]==32) l--;
				}
			}
			if (buffer[j]==0xd)
				Umbruch=1;
			else
				Umbruch=0;
			line[l]=0;
			for (p=strlen(line)-1; line[p]==32; p--);
			p++;
			line[p]=0;
			if (line[0]==1 || seenby || kludge)
			{
				if (buffer[j]!=0xd)
				{
					kludge=1;
					strcat(kline,line);
				} else
				{
					strcat(kline,line);
					kludge=0;
					(*Kludges)=(LineListType *)realloc((*Kludges),\
						((*KludgeLines)+1)*LineListSize);
					(*Kludges)[(*KludgeLines)].line=(char *)malloc(strlen(kline)+1);
					strcpy((*Kludges)[(*KludgeLines)].line,kline);
					(*KludgeLines)++;
					strcpy(kline,"");
				}
				if (line[0]==1) line[0]='@';
				(*DispKludges)=(LineListType *)realloc((*DispKludges),\
						((*DispKludgeLines)+1)*LineListSize);
				(*DispKludges)[(*DispKludgeLines)].line=(char *)malloc(strlen(line)+1);
				strcpy((*DispKludges)[(*DispKludgeLines)].line,line);
				(*DispKludgeLines)++;
				if (fquote)
				{
					free(fquote);
					fquote=NULL;
				}
			}	else
			{
				(*MsgTxt)=(LineListType *)realloc((*MsgTxt),\
						((*MsgLines)+1)*sizeof(LineListType));
				if (fquote)
				{
					for (ps=p=(buffer[j]==0xd || buffer[j]==32)?1:0;
							j+p<256*mh->NumRecs; p++)
						if (buffer[j+p]==0xd || buffer[j+p]==0) break;
					strncpy(newline,buffer+j+ps,p-ps);
					newline[p-ps]=0;
					if ((nquote=GetQuote(newline)))
						if (strcmp(fquote,nquote)==0)
						{
							ps=strlen(nquote);
							while (newline[ps]==32) ps++;
							if (line[strlen(line)-1]!=32)
								strcat(line," ");
							strcat(line,newline+ps);
							if (strlen(line)+strlen(fquote)+1>MAXCOLS)
							{
								for (pp=strlen(line);
										(pp>MAXCOLS-strlen(fquote)-1 ||
										!strloc(line[pp]," -,")) && pp>0; pp--, p--);
								if (!pp) pp=MAXCOLS-strlen(fquote);
								pp++;
								p++;
								line[pp]=0;
							}
							j+=p;
						}
					free(nquote);
					(*MsgTxt)[(*MsgLines)].line=(char *)malloc(strlen(fquote)+strlen(line)+2);
					strcpy((*MsgTxt)[(*MsgLines)].line,fquote);
					strcat((*MsgTxt)[(*MsgLines)].line," ");
					strcat((*MsgTxt)[(*MsgLines)].line,line);
					if (buffer[j]==0xd)
					{
						free(fquote);
						fquote=NULL;
					}
					(*MsgTxt)[(*MsgLines)].Quote=qlvl;
					Umbruch=1;
				} else
				{
					(*MsgTxt)[(*MsgLines)].line=(char *)malloc(strlen(line)+1);
					strcpy((*MsgTxt)[(*MsgLines)].line,line);
					if ((qlvl=IsQuote(line)))
					{
						(*MsgTxt)[(*MsgLines)].Quote=qlvl;
						if (!Umbruch)
						{
							if ((fquote=GetQuote(line)))
								if (strlen(fquote)>=MAXCOLS)
								{
									free(fquote);
									fquote=NULL;
								}
						}
						Umbruch=1;
					} else
						(*MsgTxt)[(*MsgLines)].Quote=0;
				}
				(*MsgTxt)[(*MsgLines)].CR=Umbruch;
				if (strncmp((*MsgTxt)[(*MsgLines)].line,"--- ",4)==0 ||
						strcmp((*MsgTxt)[(*MsgLines)].line,"---")==0)
					(*MsgTxt)[(*MsgLines)].CutOrigin=1;
				else
				{
					if (strncmp((*MsgTxt)[(*MsgLines)].line," * Origin:",10)==0)
						(*MsgTxt)[(*MsgLines)].CutOrigin=2;
					else
						(*MsgTxt)[(*MsgLines)].CutOrigin=0;
				}
				(*MsgLines)++;
			}
			l=n=line[0]=seenby=0;
			if (buffer[j]==0xd || strloc(buffer[j]," -,")) j++;
			if (buffer[j]==0) break;
		}
	}
	free(buffer);
}

void killTextOfMsg(int *MsgLines, LineListType **MsgTxt,
		int *KludgeLines, LineListType **Kludges,
		int *DispKludgeLines, LineListType **DispKludges)
{
	int j;
	if ((*MsgTxt))
		for (j=0; j<(*MsgLines); j++) free((*MsgTxt)[j].line);
	free((*MsgTxt));
	if ((*Kludges))
		for (j=0; j<(*KludgeLines); j++) free((*Kludges)[j].line);
	free((*Kludges));
	if ((*DispKludges))
		for (j=0; j<(*DispKludgeLines); j++) free((*DispKludges)[j].line);
	free((*DispKludges));
	(*MsgTxt)=(*Kludges)=(*DispKludges)=NULL;
	(*MsgLines)=(*KludgeLines)=(*DispKludgeLines)=0;
}

void initquote()
{
	memset(&_QUOTE_regexp,0,sizeof(struct re_pattern_buffer));
	re_set_syntax(RE_SYNTAX_POSIX_EGREP);
	if (re_compile_pattern(_QUOTE,strlen(_QUOTE),&_QUOTE_regexp))
		_QUOTE_on=0;
	else
		_QUOTE_on=1;
}

int IsQuote(char *s)
{
	struct re_registers regs;
	int lvl=0, i;
	if (*s)
	{
		regs.num_regs=0;
		regs.start=regs.end=NULL;
		if (_QUOTE_on)
			if (re_match(&_QUOTE_regexp,s,strlen(s),0,&regs)>=0)
			{
				for (i=regs.start[0]; i<regs.end[0]; i++)
					if (s[i]=='>') lvl++;
				free(regs.start);
				free(regs.end);
			}
	}
	return lvl;
}

int GetQuotePos(char *s)
{
	struct re_registers regs;
	int res=0;
	if (*s)
	{
		regs.num_regs=0;
		regs.start=regs.end=NULL;
		if (_QUOTE_on)
			if (re_match(&_QUOTE_regexp,s,strlen(s),0,&regs)>=0)
			{
				res=regs.end[0]+1;
				free(regs.start);
				free(regs.end);
			}
	}
	return res;
}

char *GetQuote(char *s)
{
	struct re_registers regs;
	char *r=NULL;
	if (*s)
	{
		regs.num_regs=0;
		regs.start=regs.end=NULL;
		if (_QUOTE_on)
			if (re_match(&_QUOTE_regexp,s,strlen(s),0,&regs)>=0)
			{
				r=(char *)malloc(regs.end[0]-regs.start[0]+1);
				strncpy(r,s+regs.start[0],regs.end[0]-regs.start[0]);
				r[regs.end[0]-regs.start[0]]=0;
				free(regs.start);
				free(regs.end);
			}
	}
	return r;
}

char *TransQuote(char *s)
{
	struct re_registers regs;
	char *r=NULL;
	int i;
	if (*s)
	{
		regs.num_regs=0;
		regs.start=regs.end=NULL;
		if (_QUOTE_on)
			if (re_match(&_QUOTE_regexp,s,strlen(s),0,&regs)>=0)
			{
				r=(char *)malloc(regs.end[0]+10);
				strcpy(r," ");
				strncat(r,&(s[regs.start[2]]),regs.end[2]-regs.start[2]);
				r[regs.end[2]-regs.start[2]+1]=0;
				for (i=regs.start[0]; i<regs.end[0]; i++)
					if (s[i]=='>') strcat(r,">");
				strcat(r,"> ");
				free(regs.start);
				free(regs.end);
				regs.num_regs=0;
			}
	}
	return r;
}
