#include "microdot.h"
#include "asyncio.h"

#include "ogre.h"
#include "ogre_protos.h"
#include <exec/execbase.h>

#include "asyncio.h"

/*static struct NewWindow snw={0,0,400,92, (UBYTE)-1,(UBYTE)-1, CLOSEWINDOW, WINDOWCLOSE|WINDOWDRAG|RMBTRAP|NOCAREREFRESH,0,0, "Einsortieren...",0,0,0,0,0,0,CUSTOMSCREEN};*/

#define text(x,y,s) Move(srp,x,y+topborderoffs);Text(srp,s,strlen(s))
#define apen(p) SetAPen(srp,p)
#define bpen(p) SetBPen(srp,p)
#define drmd(m) SetDrMd(srp,m)
#define move(x,y) Move(srp,x,y)
#define draw(x,y) Draw(srp,x,y)

static struct List mkelist;
static void *mkerk;
static struct MinList mixlist;	/* Liste aller Indizies */

/*static struct MinList mailerlist;
static void *mailerlistpool;
static ULONG nomailercounter;*/


struct mailernode
{
	struct MinNode	n;			/* Link Node */
	ULONG			counter;	/* Counter */
	UBYTE			cmps[18];	/* Compare-String */
	UWORD			cmpl;		/* Compare-Länge */
};

static long zctime(char *z)
{
	char x[6],tmp[6];
	int c;
	time_t t,t2;

	tmp[2]=0;
	for(c=1; c<6; c++)
	{
		tmp[0]=z[c*2+2];
		tmp[1]=z[c*2+3];
		x[c]=atoi(tmp);
	}
	tmp[0]=z[0];
	tmp[1]=z[1];
	tmp[2]=z[2];
	tmp[3]=z[3];
	tmp[4]=0;
	x[0]=atoi(tmp)-1970;
	t=utpack(x);

	/* Ok, in t ist jetzt die GMT der Nachricht */
	/* Unsere Zeitzone rausfinden */

	t += timezone_offset;

	time(&t2);
	if(t>t2) t=t2;

	return((long)t);
}


#if 0
static void initmailercounter( void )
{
	NewList( ( struct List * ) &mailerlist );
	mailerlistpool = LibCreatePool( NULL, sizeof( struct mailernode ) * 16, sizeof( struct mailernode ) * 8 );
	nomailercounter = 0;
}

static void addmailercounter( char *txt )
{
	struct mailernode *mn = ( struct mailernode *) mailerlist.mlh_Head;
	char *p;
	char buffer[24];

	if( !txt || !txt[0] )
	{
		nomailercounter++;
		return;
	}

	while( mn->n.mln_Succ )
	{
		if( !strnicmp( mn->cmps, txt, mn->cmpl ) )
		{
			mn->counter++;
			return;
		}
		mn = (struct mailernode *) mn->n.mln_Succ;
	}

	/* Neue Struktur erzeugen */
	strncpy( buffer, txt, 17 );
	buffer[ 17 ] = 0;
	p = strchr( buffer, ' ' );
	if( !p )
		p = strchr( buffer, '\t' );
	if( !p )
		p = strchr( buffer, '-' );
	if( !p )
		p = strchr( buffer, '[' );
	if( !p )
		p = strchr( buffer, '(' );
	if( p )
		*p = 0;

	if( !strlen( buffer ) )
	{
		nomailercounter++;
		return;
	}

	mn = LibAllocPooled( mailerlistpool, sizeof( struct mailernode ) );
	if( !mn )
		return;

	strcpy( mn->cmps, buffer );
	mn->cmpl = strlen( buffer );
	mn->counter = 1;
	AddTail( ( struct List *) &mailerlist, ( struct Node *) mn );
}
#endif

#if 0
static char *makefilenum( int n )
{
	static char fns[ 16 ];

	sprintf( fns, "%ld", n );
	return( fns );
}
#endif

#define PERC(x,m) ((m)?(((x)*100)/m):0)
#if 0
static void reportmailercounter( int mailcount )
{
	struct mailernode *mn = ( struct mailernode *) mailerlist.mlh_Head;
	char buffer[ 20 ];

	if( nomailercounter )
		printlog( "Anteil Nachrichten ohne MAILER:-Zeile....: %ld%% (%ld von %ld Nachrichten)\n",
			PERC( nomailercounter, mailcount ),
			nomailercounter,
			mailcount
		);

	buffer[ 17 ] = 0;
	while( mn->n.mln_Succ )
	{
		memset( buffer, '.', 17 );
		memcpy( buffer, &mn->cmps[0], mn->cmpl );
		printlog( "Anteil Nachrichten von %s.: %ld%% (%ld von %ld Nachrichten)\n",
			buffer,
			PERC( mn->counter, mailcount ),
			mn->counter,
			mailcount
		);

		mn = (struct mailernode *) mn->n.mln_Succ;
	}

	printlog( "\n" );
	LibDeletePool( mailerlistpool );
}
#endif

/* Msg-ID in Killiste einfügen */
void addmke(char *id)
{
	long t;
	FILE *f;

	pushhomedir();
	f = fopen("microdot.kill","a");
	if(!f) f=fopen("microdot.kill","w");
	popdir();
	if( !f )
	{
		displaybeep();
		return;
	}
	time(&t);
	fwrite(&t,4,1,f);
	fprintf(f,"%s\n",id);
	fclose(f);
}

struct mke {
	struct MinNode n;
	ULONG crc32;
	char mid[2];
};

static void addmkemem(char *id)
{
	struct mke *n = LibAllocPooled(mkerk,sizeof(struct mke)+strlen(id)-1);
	if( !n )
		return;
	n->crc32 = crc32( id, strlen( id ) );
	strcpy( n->mid, id );
	AddTail( &mkelist, ( struct Node * ) n );
}

void loadmke(void)
{
	FILE *f;
	char buffer[1024];

	NewList( &mkelist );
	mkerk = LibCreatePool( 0, 1024, 512 );
	if( !mkerk )
		return;
	pushhomedir();
	f = fopen( "microdot.kill", "r" );
	popdir();
	if( !f )
		return;

	fsetbuf( f, 8192 );
	for(;;)
	{
		if( fread( buffer, 4, 1, f ) < 1 )
			break;
		if( !fgets( buffer, 1024, f ) )
			break;
		clnl( buffer );
		addmkemem( buffer );
	}
	fclose(f);
}

void freemke(void)
{
	if( mkerk )
	{
		LibDeletePool(mkerk);
		mkerk=0;
	}
}

int testidmke(char *id)
{
	struct mke *n=(struct mke*)mkelist.lh_Head;
	long crc=crc32(id,strlen(id));

	while(n->n.mln_Succ)
	{
		if(n->crc32==crc && !strcmp(n->mid,id)) return(-1);
		n=(struct mke*)n->n.mln_Succ;
	}
	return(0);
}

int testcrcidmke(long crc)
{
	struct mke *n=(struct mke*)mkelist.lh_Head;

	while(n->n.mln_Succ) {
		if(n->crc32==crc) return(-1);
		n=(struct mke*)n->n.mln_Succ;
	}
	return(0);
}

static struct MinList ukl;
static void *ukpool;
struct ukn {
	struct MinNode n;
	UBYTE flags;
	UBYTE len;
	char killpath[118];
};

void loaduk(void)
{
	FILE *f;
	char buffer[128];
	struct ukn *n;

	NewList( (struct List*) &ukl );
	ukpool=LibCreatePool( 0, 2048, 1024 );
	pushhomedir();
	f=fopen("microdot.killuser","r");
	popdir();
	if(!f) return;
	fsetbuf(f,2048);
	while(fgets(buffer,128,f))
	{
		clnl(buffer);
		if(strlen(buffer)<3) continue;
		n=LibAllocPooled(ukpool,sizeof(struct ukn));
		if(!n) break;
		n->flags=strchr(buffer,'*')||strchr(buffer,'?');
		n->len=strlen(buffer);
		strncpy(n->killpath,buffer,117);
		AddTail(&ukl,n);
	}
	fclose(f);
}

void freeuk(void)
{
	if(ukpool) {
		LibDeletePool(ukpool);
		ukpool=0;
	}
}

static int testuk(char *abs)
{
	struct ukn *n=(struct ukn*)ukl.mlh_Head;

	while(n->n.mln_Succ)
    {
		if(n->flags)
        {
			if(stcsma(abs,n->killpath)) return(-1);
		}
		else {
			if(!strnicmp(abs,n->killpath,n->len)) return(-1);
		}
		n=(struct ukn*)n->n.mln_Succ;
	}
	return(0);
}

void hl_freeheader( struct hlist *hl )
{
	if( hl )
		LibDeletePool( hl->pool );
}
/*void freeheader( void )
{
	hl_freeheader( defhl );
	defhl = NULL;
}
*/

struct hlist *hl_initheader( void )
{
	void *pool;
	struct hlist *hl;

	pool = LibCreatePool( MEMF_CLEAR, 2048, 512 );
	if( !pool )
		return( NULL );
	hl = LibAllocPooled( pool, sizeof( *hl ) );
	if( !hl )
		return( NULL );
	NewList( ( struct List * ) &hl->l );
	hl->pool = pool;
	return( hl );
}

void hl_clearhlist( struct hlist *hl )
{
	NewList( ( struct List * ) &hl->l );
}


/*void initheader( void )
{
	freeheader();
	defhl = hl_initheader();
}*/

/*#define delheader hl_delheader*/
void hl_delheader( struct header *head )
{
	Remove( head );
}

void hl_addheader( struct hlist *hl, char *head,char *data)
{
	struct header *n;

	n = LibAllocPooled(hl->pool,sizeof(struct header));
	if(!n)
	{
		displaybeep();
		return;
	}

	n->head=LibAllocPooled(hl->pool,strlen(head)+1);
	strcpy(n->head,head);
	if(data)
	{
		n->data=LibAllocPooled(hl->pool,strlen(data)+1);
		strcpy(n->data,data);
	}

	AddTail( &hl->l, (struct Node*)n );
}

struct header *hl_findheader(struct hlist *hlist, char *name)
{
	struct header *hl=(struct header*)hlist->l.mlh_Head;

	if(!name)
	{
		if( hl->n.mln_Succ )
			return( hl );
		else
			return( NULL );
	}

	while(hl->n.mln_Succ)
	{
		if(!stricmp(name,hl->head)) return(hl);
		hl=(struct header*)hl->n.mln_Succ;
	}
	return(0);
}

int hl_testheader( struct hlist *hlist, char *header, char *contents )
{
	struct header *hl = hl_findheader( hlist, header );

	while( hl )
	{
		if( !contents )
			return( -1 );
		if( !stricmp( contents, hl->data ) )
			return( -1 );
		hl = hl_findnextheader( hl );
	}
	return( 0 );
}

/*
struct header *hl_findlastheader(struct hlist *hlist, char *name)
{
	struct header *hl=(struct header*)hlist->l.mlh_TailPred;

	if(!name)
	{
		if( hl->n.mln_Pred )
			return( hl );
		else
			return( NULL );
	}

	while(hl->n.mln_Pred)
	{
		if(!strcmp(name,hl->head)) return(hl);
		hl=(struct header*)hl->n.mln_Pred;
	}
	return(0);
}
*/

struct header *hl_nextheader( struct header *hl )
{
	hl = ( struct header * ) hl->n.mln_Succ;

	if( hl->n.mln_Succ )
		return( hl );
	else
		return( NULL );

}

/*struct header *findheader(char *name)
{
	return( hl_findheader( defhl, name ) );
}*/

struct header *hl_findlastheader(struct hlist *hlist,char *name)
{
	struct header *hl=(struct header*)hlist->l.mlh_Head;
	struct header *last=NULL;

	if(!name) return(hl);

	while(hl->n.mln_Succ)
	{
		if(!stricmp(name,hl->head)) last=hl;
		hl=(struct header*)hl->n.mln_Succ;
	}
	return(last);
}
/*struct header *findlastheader(char *name)
{
	return( hl_findlastheader( defhl, name ) );
}*/

struct header *hl_findnextheader(struct header *hl)
{
	char *name=hl->head;

	if(!hl->n.mln_Succ) return(0);
	hl=(struct header*)hl->n.mln_Succ;
	while(hl->n.mln_Succ) {
		if(!stricmp(name,hl->head)) return(hl);
		hl=(struct header*)hl->n.mln_Succ;
	}
	return(0);

}

static int hl_dumpheaderasync( struct hlist *hlist, struct AsyncFile *to )
{
	struct header *hl=(struct header*)hlist->l.mlh_Head;
	int len = 0;

	while(hl->n.mln_Succ)
	{
		WriteAsync( to, hl->head, strlen( hl->head ) );
		WriteCharAsync( to, ':' );
		WriteAsync( to, hl->data, strlen( hl->data ) );
		WriteCharAsync( to, '\n' );
		len += strlen( hl->head ) + strlen( hl->data ) + 2;
		hl=(struct header*)hl->n.mln_Succ;
	}
	WriteCharAsync( to, '\n' );

	return( len + 1 );
}

int hl_dumpheaderpf( struct hlist *hlist, struct AsyncFile *to )
{
	struct header *hl=(struct header*)hlist->l.mlh_Head;
	struct pfhandle *pfh;

	pfh = pf_open( to, TRUE, prefs.do_packmsg, 0 );

	while(hl->n.mln_Succ)
	{
		pf_write( pfh, hl->head, strlen( hl->head ) );
		pf_writech( pfh, ':' );
		pf_write( pfh, hl->data, strlen( hl->data ) );
		pf_writech( pfh, '\n' );
		
		hl=(struct header*)hl->n.mln_Succ;
	}
	pf_writech( pfh, '\n' );

	return( pf_close( pfh ) );
}


int hl_dumpheaderfile( struct hlist *hlist, BPTR to )
{
	struct header *hl=(struct header*)hlist->l.mlh_Head;
	int len = 0;

	while(hl->n.mln_Succ)
	{
		Write( to, hl->head, strlen( hl->head ) );
		Write( to, ":", 1 );
		Write( to, hl->data, strlen( hl->data ) );
		Write( to, "\n", 1 );
		len += strlen( hl->head ) + strlen( hl->data ) + 2;
		hl=(struct header*)hl->n.mln_Succ;
	}
	Write( to, "\n", 1 );

	return( len + 1 );
}

int hl_dumpheaderfp( struct hlist *hlist, FILE *to )
{
	struct header *hl=(struct header*)hlist->l.mlh_Head;
	int len = 0;

	while(hl->n.mln_Succ)
	{
		fprintf( to, "%s:%s\n", hl->head, hl->data );
		len += strlen( hl->head ) + strlen( hl->data ) + 2;
		hl=(struct header*)hl->n.mln_Succ;
	}
	putc( '\n', to );
	return( len + 1 );
}


/*int dumpheaderfile( BPTR to )
{
	return( hl_dumpheaderfile( defhl, to ) );
}*/


static void copysomebytes(struct AsyncFile *from,struct pfhandle *to,long len)
{
	void *buffer;
	long bufflen,rc;

	buffer = allocbuffmem( len, &bufflen );

	while( len > 0 )
	{
		rc = ReadAsync( from, buffer, min( len, bufflen ) );
		if( rc > 0 )
			pf_write( to, buffer, rc );
		else
			break;
		len -= rc;
	}
	freebuffmem();
}

static UBYTE decodech( UBYTE ch )
{
	ch ^= (UBYTE) rand();
	return( ch );
}

static void decodeblock( UBYTE *block, int size )
{
	while( size-- )
		*block++ ^= (UBYTE) rand();	
}

static int copymsg(struct AsyncFile*from,struct AsyncFile*to,long maillen,BOOL bin, BOOL coded, ULONG code, BOOL isiso )
{
	int ch;
	struct pfhandle * pfh;

	if( maillen > 0 )
	{
		pfh = pf_open( to, TRUE, prefs.do_packmsg, 0 );

		if( bin && !coded )
		{
			copysomebytes( from, pfh, maillen );
			return( pf_close( pfh ) );
		}

		if( coded )
		{
			srand( code );
			while( maillen-- )
			{
				ch = ReadCharAsync( from );
				if( ch < 0 )
					break;
				ch = decodech( ch );
				pf_writech( pfh, ch );
			}
		}
		else while(maillen--)
		{
			ch = ReadCharAsync( from );
			if( ch < 0 )
				break;
			if( ch == 13 )
				continue;
			if( !isiso )
				ch = ibm2iso( ch );
			pf_writech( pfh, ch );
		}
		return( pf_close( pfh ) );
	}

	return( 0 );
}

static int copyqp( struct AsyncFile *from, struct AsyncFile *to, long maillen )
{
	int ch;
	struct pfhandle * pfh;

	if( maillen > 0 )
	{
		pfh = pf_open( to, TRUE, prefs.do_packmsg, 0 );

		while( maillen-- > 0 )
		{
			ch = ReadCharAsync( from );
			if( ch < 0 )
				break;
			if( ch == 13 )
				continue;

			if( ch == '=' )
			{
				char x[ 4 ];

				x[ 0 ] = ReadCharAsync( from );
				if( x[ 0 ] == 10 )
				{
					maillen--;
					continue;
				}

				x[ 1 ] = ReadCharAsync( from );
				if( x[ 1 ] == 10 )
				{
					maillen -= 2;
					continue;
				}

				x[ 2 ] = 0;
				stch_l( x, (long)&ch );

				maillen -= 2;
			}

			pf_writech( pfh, ch );
		}
		return( pf_close( pfh ) );
	}

	return( 0 );
}

static int copymsg2pgp( struct AsyncFile * from, char *to, long maillen )
{
	struct AsyncFile *tofile = OpenAsync( to, MODE_WRITE, 8192 );
	int size = 0, rc;
	char buffer[ 1024 ];

	if( tofile )
	{
		while( maillen > 0 )
		{
			rc = ReadAsync( from, buffer, min( maillen, 1024 ) );
			if( rc <= 0 )
				break;
			size += rc;
			maillen -= rc;
			WriteAsync( tofile, buffer, rc );
		}
		CloseAsync( tofile );
	}
	return( size );
}


/* ID-Format:

	X<achtstelligeCRC32><X><vierstelligeVersion><020Flag><X>FF<&>
    012345678            9  10                   14       1516


    crc = crc32^DC00DCF2 gleichzeitig codeschlüssel
    version = 4x hex ^ 7777
    _ == 020, ! == normal
	& == gepackt

	PatchTAG:

    \xABCDEF77 2000f013

*/

#if 0
ULONG __aligned patchtag[]={0x00000a80,0xffefffef,0x00064e75,0xffffa0cf,0xffffe040,0xabcdef77,0x2000f013};
static ULONG *patchtagptr;

static void copyeor(ULONG *to,ULONG *from,int lw)
{
	while(lw--) *to++=(*from++)^0xffffffff;
}

static void findpatchtag( ULONG *buffer, long len )
{
	while(len--)
	{
		if(*buffer==0x2000f013 && buffer[-1]==0xabcdef77)
		{
			patchtagptr=&buffer[-6];
			break;
		}
		buffer++;
	}
}

static void decode(ULONG *buffer,long len)
{
	while(len--) {
		*buffer^=rand();
		if(*buffer==0x2000f013 && buffer[-1]==0xabcdef77)
			patchtagptr=&buffer[-6];
		buffer++;
	}
}

static void doextractkey(char *msgname,char *id)
{
	long maillen,headoffs;
	void *mailbuf;
	BPTR f;
	LONG decodedkey[256], chk = 0;
	int keylen, longlen;
	int c;

	maillen = getfilelen( msgname );
	if( maillen<64 ) return;
	f=Open(msgname,MODE_OLDFILE);
	if(!f) {
		return;
	}
	Read( f, &headoffs, 4 );
	Seek( f, headoffs, OFFSET_BEGINNING );
	maillen-=headoffs;
	mailbuf=AllocMem(maillen,0);
	if(!mailbuf)
	{
		Close(f);
		return;
	}
	Read(f,mailbuf,maillen);
	Close(f);

	/* In Mailbuf steht jetzt der gepackte Key */
	keylen = lzw_unpack( mailbuf, decodedkey );

	FreeMem(mailbuf,maillen);

	if( keylen & 3)
		return;

	/* Patchen... */
	copyeor( ( ULONG * ) &decodedkey[10], (ULONG *) prefs.pointname, 24/4 );

	longlen = decodedkey[7];
	decodedkey[9] = NULL;
	for( c = 0; c < longlen; c++ )
		chk += decodedkey[ 8 + c ];
	decodedkey[9] = -chk;

	/* Extrahieren */

	f=Open("microdot.key",MODE_NEWFILE);
	if(f)
	{
		Write(f,decodedkey,keylen);
		Close(f);
	} 

	time( &prefs.registertime );

	printlog("\nMicroDot-Key eingegangen und installiert.\n\n");

	doregister();

	sendshortmail( "MicroDOT-Keys@TECMANIA.rara.sub.org", "Keyack", 
		"!", NULL, NULL, NULL, 0 );

	askreq( "Ihr Keyfile \"microdot.key\" ist angekommen und installiert.\n\nDamit ist diese Version von MicroDot registriert und die\nerweiterten Funktionen sind aktiviert.\n\nBitte vergessen Sie nicht, daß das Keyfile ausschließlich\nmit ihrer Version von MicroDot verwendet werden darf\nund das die Weitergabe des Keyfiles verboten ist!", "OK" );

}

static void installupdate( ULONG crc1, ULONG crc2, ULONG mdver, ULONG v20 )
{
	ULONG mdv1, mdv2;
	char *v20string = "";
	int rc;

	mdv1 = mdver >> ( 3 * 4 );
	mdv2 = mdver & 0xfff;

	if( !registerinfo.serie )
		return;

	if( v20 )
		v20string = "(für 68020, OS 3.0 und höher) ";

	if( mdver <= MDUPDVER )
	{
		if( !askreq("Hinweis: Die als automatisches Update eingegangene\nMicroDot-Version %lx.%ld %sist älter als die hier\ninstallierte Version " MDVER "!","Trotzdem weiter|Update ignorieren",mdv1, mdv2, v20string, MDUPDVER ) )
			return;
	}

	if( crc1 != crc2 )
	{
		askreq("Fehler: Die als automatisches Update eingegangene\nDatei hat einen Prüfsummenfehler.","Update ignorieren");
		return;
	}

	if( v20 && ( !isv39 || !(SysBase->AttnFlags&(AFF_68020|AFF_68030|AFF_68040) ) ) )
	{
		askreq("Hinweis: Die als automatisches Update eingegangene\nMicrodotAGA-Version %lx.%lx ist für Systeme mit OS 3.0 sowie 68020\noder höheren Prozessoren und\ndaher auf Ihrem Rechner nicht lauffähig.","Update ignorieren", mdv1, mdv2 );
		return;
	}

	rc = askreq( "Möchten Sie die als automatisches Update\neingegangene MicroDot-Version %lx.%lx %s\nsofort installieren oder es nur unter dem Namen\n\"MicroDot_Update.V%lx\"\nablegen und später von Hand installieren?",
 		"Sofort Installieren|Ab_legen|Komplett Ignorieren",
		mdv1, mdv2, v20string, mdver );

	if( rc == 1 )	
	{
		DeleteFile( "MicroDot.OLD" );
		Rename( progname, "MicroDot.OLD" );
		copyicon( progname, "MicroDot.OLD" );
		Rename( "microdot.update", progname );
		askreq( "MicroDot-Version %lx.%lx wurde installiert\nund wird beim nächsten Neustart\nvon MicroDot aktiviert.\nDie alte Version wurde unter\ndem Namen \"MicroDot.OLD\" gesichert.",
			"Ok",
			mdv1, mdv2
		);
	}
	else if( rc == 2 )
	{
		char toname[ 256 ];

		sprintf( toname, "MicroDot_Update.V%lx", mdver );
		DeleteFile( toname );
		Rename( "microdot.update", toname );
		copyicon( progname, toname );
		askreq( "MicroDot-Version %lx.%lx wurde unter dem Namen\n\"%s\" gesichert.", "Ok", mdv1, mdv2, toname );
	}
	return;
}

static void doextractupdate(char *msgname,char *id)
{
	long maillen,headoffs;
	void *mailbuf;
	char buff[32];
	ULONG crc,targetcrc,mdver,v20;
	int iscomp;
	BPTR f;

	if( !registerinfo.serie )
		return;

	patchtagptr = NULL;

	maillen = getfilelen( msgname );
	if( maillen < 128000 )
		return;
	if( strlen( id )<18 )
		return;

	strcpy(buff,id);
	buff[9]=0;
	v20=(buff[14]=='_');
	iscomp = ( buff[18] == '&' );

	/* V20 bringt nix für diesen Rechner */
	if( v20 && (! ( SysBase->AttnFlags & ( AFF_68020 | AFF_68030 | AFF_68040 ) ) ) )
		return;

	buff[14]=0;
	stch_l(&buff[1], ( LONG *) &targetcrc);
	stch_l(&buff[10], ( LONG *) &mdver);

	srand( targetcrc );
	registerinfo.func1( &targetcrc );
	/*targetcrc^=0xdc00dcf2;*/
	mdver^=0x7777;

	f=Open(msgname,MODE_OLDFILE);
	if(!f) {
		return;
	}
	Read(f,&headoffs,4);
	Seek(f,headoffs,OFFSET_BEGINNING);
	maillen-=headoffs;
	mailbuf=AllocMem(maillen,0);
	if(!mailbuf)
	{
		Close(f);
		return;
	}
	Read(f,mailbuf,maillen);
	Close(f);

	decode( mailbuf, maillen/4 );
	crc=crc32(mailbuf,maillen);

	/* Gut, gepackte & kodierte Mail steht jetzt im Mailbuf */

	if( iscomp )
	{
		long unpacklen = *((long*) mailbuf);
		void *unpackbuf;

		unpackbuf = AllocMem( unpacklen, 0 );
		lzw_unpack( (UBYTE*)mailbuf + 4, unpackbuf );

		FreeMem( mailbuf, maillen );

		mailbuf = unpackbuf;
		maillen = unpacklen;

		/* Patchtag finden */

		findpatchtag( unpackbuf, maillen / 4 );
	}

	/*if(!patchtagptr) ColdReboot();*/
	copyeor( patchtagptr, ( ULONG * ) prefs.pointname, 24/4);

	/* Extrahieren */

	f = Open( "microdot.update", MODE_NEWFILE );
	if(f)
	{
		Write( f, mailbuf, maillen );
		Close( f );
	} 
	FreeMem( mailbuf, maillen );

	printlog("\nMicroDot-Update eingegangen: Version %lx %s\n\n",mdver,(v20)?"(für 68020 und höher)":"");

	installupdate( crc, targetcrc, mdver, v20 );
	
}
#endif

static ULONG calcmcrc( char *id )
{
	char tmpmid[ 128 ];
	char *p;

	strncpy( tmpmid, id, 127 );
	tmpmid[ 127 ] = 0;

	p = strchr( tmpmid, '@' );
	if( p )
		strlwr( p );

	return( crc32( tmpmid, strlen( tmpmid ) ) );
}

/* != 0 == foundid */
static int markgoteb( char *bezid, struct hlist *fromhlist )
{
	ULONG bezcrc;
	struct mbrett *mb;
	struct mindex *mix;
	struct mmail *m;
	struct msghandle *msg;
	struct hlist *hlist;
	struct header *hl;

	bezcrc = calcmcrc( bezid );

	mb = findpmbrett( fromhlist );
	mix = loadbrettixquiet( mb );
	if(mix)
	{
		m=(struct mmail*)mix->maillist.lh_Head;
		while(m->n.mln_Succ)
		{
			if( m->m.midcrc == bezcrc )
			{
				// Gefunden
				msg = msg_open( m->m.pufferID, m->m.mailID );
				if( msg )
				{
					hlist = msg_loadheader( msg );
					if( hlist )
					{
						hl = hl_findheader( hlist, "EMP" );
						if( hl && hl_findnextheader( hl ) )
						{
							hl_freeheader( hlist );
							msg_close( msg );
							freebrettix( mix );
							return( 0 );
						}
						hl_freeheader( hlist );
					}
					msg_close( msg );
				}
				m->m.flags |= MMF_GOTEB;
				mix->changed = 1;
				savebrettix( mix, mb );
				freebrettix( mix );
				return(-1);
			}
			m=(struct mmail*)m->n.mln_Succ;
		}
		freebrettix(mix);
	}
	return(0);
}

int isfrommicrodot( struct hlist *hlist )
{
	struct header *hl=hl_findheader(hlist,"MAILER");

	return(hl && hl->data &&!strnicmp(hl->data,"MicroDot",8));
}

static BPTR ifg_lock;
static struct InfoData *ifg_id;
static struct ogwin *ifg_ogw;
static int ifg_gad_id;
void setupinfofg( char *path, struct ogwin *ogw, int id )
{
	ifg_lock = Lock( path, SHARED_LOCK );
	if( !ifg_lock )
		ifg_lock = Lock( "", SHARED_LOCK );
	ifg_id = AllocMem( sizeof( *ifg_id ), MEMF_CLEAR | MEMF_PUBLIC );
	ifg_ogw = ogw;
	ifg_gad_id = id;
}
void freeinfofg( void )
{
	if( ifg_lock )
		UnLock( ifg_lock );
	if( ifg_id )
		FreeMem( ifg_id, sizeof( *ifg_id ) );
}
void doinfofg( void )
{
	if( !ifg_lock || !ifg_id )
		return;
	if( !Info( ifg_lock, ifg_id ) )
		return;

	ogreSetMaxVal( ifg_ogw, ifg_gad_id, ifg_id->id_NumBlocks );
	ogreSetValue( ifg_ogw, ifg_gad_id, ifg_id->id_NumBlocksUsed );
}

/* nächsten freien Puffer suchen */
int getnextfreepuf( void )
{
	char buf[ 32 ];
	int c;
	BPTR testlock;
	struct FileInfoBlock *fib = allocfib();

	pushdir( prefs.datadir );

	for( c = prefs.nextfreepuf; ; c++ )
	{
		sprintf( buf, "MD_%lx.DATA", c );
		testlock = Lock( buf, SHARED_LOCK );
		if( testlock )
		{
			Examine( testlock, fib );
			UnLock( testlock );
			if( fib->fib_Size < 3 )
				break;
		}
		else
		{
			if( IoErr() == ERROR_OBJECT_NOT_FOUND )
				break;
		}
	}

	popdir();

	freefib( fib );

	prefs.nextfreepuf = c + 1;

	return( c );
}

void header2mail( struct hlist *hlist, struct mail *mail )
{
	char *p,*p2,*p3;
	struct header *hl, *hl2;

	/*memset( &mail, 0, sizeof( mail ) );*/

	time( &mail->incomtime );
	mail->flags |= MMF_UNSEEN;

	hl = hl_findheader( hlist, "LEN" );
	if( hl )
		mail->maillen = atoi( hl->data );

	hl = hl_findheader( hlist, "ABS" );
	if( !hl )
	{
		hl = hl_findheader( hlist, "EMP" );
		strcpy( mail->absender, "an " );
		strncat( mail->absender, hl ? hl->data : "???", 39 - 4 );
		mail->flags |= MMF_OUT;

		if( prefs.flags2 & MDF2_HOLDOWNMAILS )
			mail->flags |= MMF_ARCHIVE;

	}
	else
	{
		p = hl->data;
		p2 = strchr(p,' ');
		if(p2)
		{
			*p2++=0;
			p2=strchr(p2,'(');
			if(p2)
			{
				p2++;
				p3=strchr(p2,')');
				if(p3) *p3=0;
				strncpy( mail->absenderreal,p2,31);
			}
		}
		strncpy( mail->absender,p,39);

	}

	hl = hl_findheader( hlist, "BET" );
	if( hl )
		strncpy( mail->betreff, hl->data, 47 );

	hl = hl_findheader( hlist, "EDA" );
	if( hl )
		mail->time = zctime( hl->data );

	hl = hl_findheader( hlist, MDCRYPTHEADER );
	if( hl )
	{
		mail->flags |= MMF_MDCRYPT;
	}
	else
	{
		hl = hl_findheader( hlist, "TYP" );
		if( hl )
			mail->flags |= MMF_BIN;
	}

	hl = hl_findheader( hlist, "CRYPT" );
	if( hl && !stricmp( hl->data, "PGP" ) )
	{
		hl = hl_findheader( hlist, "CRYPT-CONTENT-TYP" );
		if( hl )
			mail->flags |= MMF_BIN;
		else
			mail->flags &= ~MMF_BIN;
		mail->flags |= MMF_PGPCRYPT;

		hl = hl_findheader( hlist, "SIGNED" );
		if( hl )
			mail->flags |= MMF_PGPSIGNED;
	}

	hl = hl_findheader( hlist, "MID" );
	if( hl )
		mail->midcrc = calcmcrc( hl->data );

	hl = hl_findlastheader( hlist, "BEZ" );
	if( hl )
	{
		mail->bezcrc = calcmcrc( hl->data );
		mail->flags |= MMF_HASBEZ;
	}

	hl2 = hl_findheader( hlist, "BEZ" );
	if( hl2 && hl2 != hl )
	{
		mail->qbezcrc = calcmcrc( hl->data );
		mail->flags |= MMF_HASQBEZ;
	}
}

static int copymailcomment( struct AsyncFile *from, struct AsyncFile *to, int len, BOOL isiso )
{
	int ch;
	struct pfhandle *pfh = pf_open( to, TRUE, prefs.do_packmsg, NULL );

	while( len-- )
	{
		ch = ReadCharAsync( from );
		if( ch == 13 )
			continue;
		if( isiso )
			pf_writech( pfh, ch );
		else
			pf_writech( pfh, ibm2iso( ch ) );
	}

	return( pf_close( pfh ) );
}

/* Sucht weiter bis wieder Nachricht */

static int findnextmailinpuffer( char *buffer, struct AsyncFile *f )
{
	BOOL gotabs = FALSE, gotmid = FALSE, gotemp = FALSE, gotbet = FALSE;
	int headeroffs = -1, offs, hl;
	char *p;

	offs = FtellAsync( f );

	while( !gotabs || !gotmid || !gotemp || !gotbet || ( headeroffs < 0 ) )
	{
		if( !FGetsAsync( f, buffer, 4096 ) ) 
			return( 0 );
		hl = strlen( buffer );
		p = strchr( buffer, ':' );
		/* Headerzeile... */
		if( p )
		{
			if( headeroffs < 0 )
				headeroffs = offs;
			*p = 0;
			if( !stricmp( buffer, "MID" ) )
				gotmid = TRUE;
			else if( !stricmp( buffer, "EMP" ) )
				gotemp = TRUE;
			else if( !stricmp( buffer, "BET" ) )
				gotbet = TRUE;
			else if( !stricmp( buffer, "ABS" ) )
				gotabs = TRUE;
		}
		else	/* Kein Header... */
		{
			gotemp = gotmid = gotbet = gotabs = FALSE;
			headeroffs = -1;
		}
		offs += hl;
	}
	SeekAsync( f, headeroffs, MODE_START );
	return( -1 );
}

/*
   Format der PGP-Header

   ULONG MDPK - ID
   ULONG strlen( userid );
   userid (zts) strlen + 1!
   ULONG crc32 über userid
   ULONG strlen( key )
   keydata (zts) strlen
   ULONG crc32 über key
*/

#define MDKID 0x4d44504b

/* Index this array by a 7 bit value to get the 6-bit binary field
 * corresponding to that value.  Any illegal characters return high bit set.
 */
static unsigned char asctobin[] = {
        0200,0200,0200,0200,0200,0200,0200,0200,
        0200,0200,0200,0200,0200,0200,0200,0200,
        0200,0200,0200,0200,0200,0200,0200,0200,
        0200,0200,0200,0200,0200,0200,0200,0200,
        0200,0200,0200,0200,0200,0200,0200,0200,
        0200,0200,0200,0076,0200,0200,0200,0077,
        0064,0065,0066,0067,0070,0071,0072,0073,
        0074,0075,0200,0200,0200,0200,0200,0200,
        0200,0000,0001,0002,0003,0004,0005,0006,
        0007,0010,0011,0012,0013,0014,0015,0016,
        0017,0020,0021,0022,0023,0024,0025,0026,
        0027,0030,0031,0200,0200,0200,0200,0200,
        0200,0032,0033,0034,0035,0036,0037,0040,
        0041,0042,0043,0044,0045,0046,0047,0050,
        0051,0052,0053,0054,0055,0056,0057,0060,
        0061,0062,0063,0200,0200,0200,0200,0200
};
#define PAD             '='

int dpem_buffer(char *inbuf, char *outbuf, int *outlength)
{
        unsigned char *bp;
        int     length;
        unsigned int c1,c2,c3,c4;
        int j;

        length = 0;
        bp = (unsigned char *)inbuf;

        /* FOUR input characters go into each THREE output charcters */

        while (*bp!='\0')
        {       if (*bp&0x80 || (c1=asctobin[*bp])&0x80)
                        return -1;
                ++bp;
                if (*bp&0x80 || (c2=asctobin[*bp])&0x80)
                        return -1;
                if (*++bp == PAD)
                {       c3 = c4 = 0;
                        length += 1;
                        if (c2 & 15)
                                return -1;
                        if (strcmp((char *)bp, "==") == 0)
                                bp += 1;
                        else if (strcmp((char *)bp, "=3D=3D") == 0)
                                bp += 5;
                        else
                                return -1;
                }
                else if (*bp&0x80 || (c3=asctobin[*bp])&0x80)
                                return -1;
                else
                {       if (*++bp == PAD)
                        {       c4 = 0;
                                length += 2;
                                if (c3 & 3)
                                        return -1;
                                if (strcmp((char *)bp, "=") == 0)
                                        ; /* All is well */
                                else if (strcmp((char *)bp, "=3D") == 0)
                                        bp += 2;
                                else
                                        return -1;
                        }
                        else if (*bp&0x80 || (c4=asctobin[*bp])&0x80)
                                return -1;
                        else
                                length += 3;
                }
                ++bp;
                j = (c1 << 2) | (c2 >> 4);
                *outbuf++=j;
                j = (c2 << 4) | (c3 >> 2);
                *outbuf++=j;
                j = (c3 << 6) | c4;
                *outbuf++=j;
        }

        *outlength = length;
        return(0);      /* normal return */

}       /* dpem_buffer */

static void addpgpkey( struct header *key, struct header *abs, struct header *userid )
{
	char buffer[ 2048 ], *p, *p2;
	char buffer2[ 2048 ];
	BPTR outfile;
	ULONG id = MDKID;
	ULONG len, klen;

	if( dpem_buffer( key->data, buffer, &klen ) )
		return;

	pushhomedir();
	outfile = Open( "MicroDot.new_pgpkeys", MODE_READWRITE );
	popdir();
	Seek( outfile, 0, OFFSET_END );

	if( userid )
	{
		FWrite( outfile, &id, 4, 1 );
		len = strlen( userid->data );
		FWrite( outfile, &len, 4, 1 );
		FWrite( outfile, userid->data, len + 1, 1 );
		len = crc32( userid->data, len );
		FWrite( outfile, &len, 4, 1 );
	}
	else
	{
		strcpy( buffer, abs->data );
		p = strchr( buffer, '(' );
		/* Tja... */
		if( !p )
		{
			Close( outfile );
			return;
		}
		p2 = strrchr( buffer, ')' );
		/* Tja... */
		if( !p2 || p + 1 > p2 )
		{
			Close( outfile );
			return;
		}
		*p2 = 0;
		*p++ = 0;

		/* Leerzeichen am Ende killen */
		for(;;)
		{
			p2 = strchr( buffer, 0 ) - 1;
			if( p2 < buffer )
				break;
			if( !isspace( *p2 ) )
				break;
			*p2 = 0;
		}

		sprintf( buffer2, "%s <%s>", p, buffer );

		FWrite( outfile, &id, 4, 1 );
		len = strlen( buffer2 );
		FWrite( outfile, &len, 4, 1 );
		FWrite( outfile, buffer2, len + 1, 1 );
		len = crc32( buffer2, len );
		FWrite( outfile, &len, 4, 1 );
	}

	/* Write Pubkey data */
	dpem_buffer( key->data, buffer, &klen );

	FWrite( outfile, &klen, 4, 1 );
	FWrite( outfile, buffer, klen, 1 );
	len = crc32( buffer, klen );
	FWrite( outfile, &len, 4, 1 );
	Close( outfile );
}

static void __asm doresetfunc( register __a0 struct mbrett *mb )
{
	mb->newmails = 0;
}

static long resetmbrettnmcounter( void )
{
	IterateList( &brettlist, doresetfunc, NULL );
}

static void __asm dodumpfunc( register __a0 struct mbrett *mb )
{
	if( mb->newmails && strcmp( mb->b.name, "/»SPOOL" ) )
	{
		printlog( "%-40.40s  %lD\n", mb->b.name, mb->newmails );
	}
}

static void dumpmbrettnmcounter( void )
{
	IterateList( &brettlist, dodumpfunc, NULL );
}

void sendpgpkey( char *user )
{
	char txt[ 128 ];

	sprintf( txt, "PGP-Public-Key von %s im Header", prefs.userrealname ); 

	sendshortmail( user, "PGP-Public-Key", txt, NULL, "STAT", "CTL", 2 );
}

static int trypgp( char *filename, char *name )
{
	static char *compressExt[] =  { ".zip",  ".zoo",  ".gif",  ".arj",
        ".hpk", ".z", ".Z", ".pak", ".hyp",
        ".lzh", ".lha", ".lzx", 0 };
	char **comp = compressExt;
	int rc;

	while( *comp )
	{
		strcpy( name, filename );
		strcat( name, *comp );
		rc = getfilelen( name );
		if( rc >= 0 )
			return( rc );
		*comp++;
	}
	return( -1 );
}

static int errorabortreq( char *reason, ULONG offset )
{
	int rc;

	rc = askreq( "Fehler beim Einsortieren:\n%s bei Offset %lD", "Sortin abbrechen|defekte Nachricht Überspringen", reason, offset );

	return( !rc );
}

static struct ogwin *ogw;
static struct Window *sw;
static dontclosesortinwin;

//
// Decode Header encoding as by RFC 2047
//
static char encodedwordmatch[ 64 ];
CONSTRUCTOR_P(initencode,7191)
{
	return( ParsePatternNoCase( "#[a-z0-9'-]'?(q|b)'?#?'?=#?", encodedwordmatch, sizeof( encodedwordmatch ) ) < 1 );
}

// decode a single QP char
int decodeqpchar( char *qpv )
{
	int val;
	int ch;

	if( *qpv == '=' )
		qpv++;
	
	ch = tolower( *qpv );
	if( ch >= 'a' && ch <= 'f' )
		val = ch - 'a' + 10;
	else
		val = ch - '0';

	val <<= 4;

	qpv++;
	ch = tolower( *qpv );
	if( ch >= 'a' && ch <= 'f' )
		val |= ch - 'a' + 10;
	else
		val |= ch - '0';

	return( val & 0xff );
}

static int decode_header( char *from, char *to )
{
	int wasencoded = FALSE;

	while( *from )
	{
		if( *from == '=' && from[ 1 ] == '?' )
		{
			// looks like start of an encoded word
			if( MatchPatternNoCase( encodedwordmatch, &from[ 2 ] ) )
			{
				int enctype = 0;

				// it actually is
				from = strchr( from + 2, '?' );

				if( !from )
					goto notencoded;

				wasencoded = TRUE;

				from++;

				// we just skipped the charset
				enctype = tolower( *from == 'b' );
				from += 2;

				// from now points to the encoded data
				if( enctype )
				{
					// base 64, currently not supported

				}
				else
				{
					for(;;)
					{
						if( !*from || ( *from == '?' && from[ 1 ] == '=' ) )
							break; // end
						if( *from == '=' && from[ 1 ] && from[ 2 ] )
						{
							// qp word
							*to++ = decodeqpchar( from + 1 );
							from = from + 3;
						}
						else if( *from == '_' )
						{
							*to++ = ' ';
							from++;
						}
						else
							*to++ = *from++;
					}
					if( *from )
						from += 2;
				}
				continue;
			}
		}
notencoded:
		*to++ = *from++;
	}
	*to = 0;

	return( wasencoded );
}

static int sortinfile2( char *file )
{
	/*struct RastPort *srp;*/
	char buff[256];
	long brettcount=0,pmcount=0,killcount=0,ebcount=0,headersize=0,gotebcount=0,realmails=0,sortedmails=0, pgpkeycount = 0, pgpkeysendcount = 0;
	struct IntuiMessage *im;
	int rc=1,c;
	struct AsyncFile *f, *f2;
	BPTR lock;
	long filelen,filepos = 0,maillen, currentheadersize;
	char buffer[ 4096 ],buffer2[ 4096 ],*p;
	char pgprealname[ 128 ];
	int bin, foundblist = FALSE, coded, foundupdate = FALSE;
	ULONG mailcode;
	struct header *hl,*hl2, *hl3;
	struct mbrett *mb;
	long stime;
	struct AsyncFile *destfile, *destix;
	struct pindex pix;
	struct mail mail;
	int currentcommentsize;
	ULONG pufID, mailID = 0;
	ULONG currentpufoffset = 0;
	struct hlist *hlist = NULL;
	ULONG mapsbl_pid, mapsbl_mid;
	ULONG mdk_pid, mdk_mid;
	BOOL pgpcrypt, ispm;
	BOOL brettthere;
	BOOL bigsort = !prefs.sortinwin_small;
	BOOL sortpmsonly = FALSE;
	BOOL isiso;
	BOOL isqp;

	if( isv37 )
	{
		if( GetVar( "MICRODOT_SORTPRIVONLY", buffer, 64, 0 ) > 0 )
		{
			if( tolower( buffer[ 0 ] ) == 'y' )
				sortpmsonly = TRUE;
		}
	}

	ixc_flush();	

	//DeleteFile( "microdot.update" );
	//DeleteFile( "microdot.updateinfo" );

	lock = Lock( file, SHARED_LOCK );
	if( !lock )
	{
		c = IoErr();
		askreq( "Fehler beim Einsortieren: Datei\n%s\nläßt sich nicht öffnen (%ld)\n%s","Abbruch",file,c, errorstring( c ) );
		return(rc);
	}
	UnLock( lock );
	filelen = getfilelen( file );

	time( &stime );
	printlog("Sortinprotokoll\n---------------\nDateiname.........: %s (%lD Bytes)\n",file,filelen);

	if( filelen < 64 )
	{
		printlog( "(Datei ignoriert)\n" );
		return( 0 );		
	}

	if( !ogw )
	{
		ogw = ogreInitWindow( scr, WFLG_ACTIVATE | WFLG_RMBTRAP | WFLG_CLOSEGADGET, IDCMP_CLOSEWINDOW, "Einsortieren..." );
		ogreAddGroup( ogw, 0, OGFRAME_OUTLINE, NULL );
		ogreAddText( ogw, 0, "Datei:", 1, "", 50, TRUE );
		ogreAddText( ogw, 1, "Mails:", 2, "", 50, TRUE );

		if( bigsort )
		{
			ogreAddGroup( ogw, 1, OGFRAME_OUTLINE, NULL );
			ogreAddText( ogw, 0, "Absender:", 3, "", 50, TRUE );
			ogreAddText( ogw, 1, "Betreff:", 4, "", 50, TRUE );
			ogreAddText( ogw, 2, "Empfänger:", 5, "", 50, TRUE );
			ogreAddText( ogw, 3, "Länge:", 6, "", 50, TRUE );
		}

		ogreAddGroup( ogw, prefs.sortinwin_small ? 1 : 2, OGFRAME_OUTLINE, NULL );
		ogreAddFuelGauge( ogw, 0, 7, filelen );
		ogreAddText( ogw, 1, "Belegter Festplattenplatz:", 8, "", 1, FALSE );
		ogreAddFuelGauge( ogw, 1, 9, 100 );

		sw = ogreOpenWindow( ogw );

		if(!sw)
		{
			return(-1);
		}
	}

	resetmbrettnmcounter();
	ogreSetMaxVal( ogw, 7, filelen ); 
	setupinfofg( prefs.datadir, ogw, 9 );

	f = OpenAsync( file, MODE_READ, 65536 );
	if( !f )
	{
		askreq( "DOS-Fehler %ld beim Öffnen von %s", "Abbruch", IoErr(), file );
		ogreExitWindow( ogw );
		ogw = NULL;
		return( -1 );
	}

	pufID = getnextfreepuf();
	sprintf( buffer, "%sMD_%lx.Data", prefs.datadir, pufID );
	destfile = OpenAsync( buffer, MODE_WRITE, 32768 );
	sprintf( buffer, "%sMD_%lx.Index", prefs.datadir, pufID );
	destix = OpenAsync( buffer, MODE_WRITE, sizeof( struct pindex ) * 64 );

	sprintf( buff, "%.27s (%lD Bytes)", filepart( file ), filelen );
	ogreSetStringValue( ogw, 1, buff );

	/*initmailercounter();*/

	doinfofg();

	for(;;)
	{
nextmail:
		memset( &pix, 0, sizeof( pix ) );
		memset( &mail, 0, sizeof( mail ) );

		pgpcrypt = FALSE;
		isqp = FALSE;
		isiso = ( prefs.mode == MDM_RFC );

		im = ogreIM( ogw );
		if(im)
		{
			if( im->Class == IDCMP_CLOSEWINDOW || ( im->Class == IDCMP_RAWKEY && im->Code == 0x45 ) )
			{
				if( askreq( "Einsortieren abbrechen?", "Abbrechen|Weitersortieren" ) )
				{
					rc=-1;
					printlog("\nEinsortieren abgebrochen!\n");
					break;
				}
			}
			ogreIMReply( ogw, im );
		}

		bin=0;

		hl_freeheader( hlist );
		hlist = hl_initheader();

		if( ! FGetsAsync( f, buffer, 4096 ) )
        {
            rc=0;
            break;
        }

		currentcommentsize = 0;

		headersize += strlen( buffer );
		currentheadersize = strlen( buffer );
		clnl( buffer );
		if( !buffer[ 0 ] )
		{
			printlog("\nHeaderzeile erwartet @%lD:\n\"%s\"\n", FtellAsync( f ), buffer );
			c = errorabortreq( "Headerzeile erwartet", FtellAsync( f ) );
			if( c )
			{
				rc = 0;
				if( findnextmailinpuffer( buffer, f ) )
					goto nextmail;
			}
			rc = 1;
			goto xit;
		}
		for( ;; )
		{
			if( strlen( buffer ) > 4093 )
			{
				strcpy( &buffer[ 4090 ], "..." );				
				printlog("\nWarnung: Überlange Headerzeile @%lD gekürzt:\n\"%s\"\n", FtellAsync( f ), buffer );
			}

/*			if( strlen( buffer ) > 4094 )
			{
				printlog("\nZu lange Headerzeile @%lD:\n\"%s\"\n", FtellAsync( f ), buffer );
				c = errorabortreq( "Zu lange Headerzeile", FtellAsync( f ) );
				if( c )
				{
					rc = 0;
					if( findnextmailinpuffer( buffer, f ) )
						goto nextmail;
				}
				rc = 1;
				goto xit;
			}*/

			p=strchr(buffer,':');
			if(!p)
			{
				printlog("\nFehlerhafte Headerzeile @%lD:\n\"%s\"\n",FtellAsync(f),buffer);
				c = errorabortreq( "Fehlerhafte Headerzeile", FtellAsync( f ) );
				if( c )
				{
					rc = 0;
					if( findnextmailinpuffer( buffer, f ) )
						goto nextmail;
				}
				rc = 1;
				goto xit;
			}
			*p++=0;
			p=stpblk(p);
			/* Header wandeln */
			sibm2iso( p );

			if( strstr( p, "=?" ) )
			{
				if( decode_header( p, buffer2 ) )
				{
					strcpy( p, buffer2 );
				}
			}

			hl_addheader(hlist,buffer,p);
			buffer[ 0 ] = 0;
			FGetsAsync(f,buffer,4096);
			headersize += strlen( buffer );
			currentheadersize += strlen( buffer );
			clnl(buffer);
			if(!buffer[0]) break; /* Ende des Headers */
		}

		hl = hl_findheader( hlist, "TYP" );
		if( hl )
			bin = TRUE;

		hl = hl_findheader( hlist, "KOM");
		if(hl)
			currentcommentsize = atoi( hl->data );

		hl = hl_findheader( hlist, "LEN" );
		if( !hl )
		{
			c = errorabortreq( "Längenangabe fehlt", FtellAsync( f ) );
			if( c )
			{
				if( findnextmailinpuffer( buffer, f ) )
					goto nextmail;
			}
			break;
		}
		maillen = atoi( hl->data ) - currentcommentsize;

		hl = hl_findheader( hlist, "MID" );
		if( !hl )
		{
			static int fakecnt;
			sprintf( buffer, "FAKE-MID-%ld-%ld@localhost", time( NULL ), fakecnt++ );
			hl_addheader( hlist, "MID", buffer );
		}

		if( bigsort )
		{
			sprintf( buff, "%lD Bytes %s ", maillen, (bin) ? "(Binär)" : "" );
			if( currentcommentsize )
				asprintf( buff, " (%lD Bytes Kommentar)", currentcommentsize );
			ogreSetStringValue( ogw, 6, buff );
		}

		hl = hl_findheader( hlist, "ABS");
		if(hl)
	        {
			if( bigsort )
				ogreSetStringValue( ogw, 3, hl->data );

			if(testuk(hl->data))
			{
				hl2 = hl_findheader( hlist, "MID" );
				if(hl2)
				{
					addmke(hl2->data);
					addmkemem(hl2->data);
				}
				killcount++;
 				SeekAsync(f,maillen+currentcommentsize,MODE_CURRENT); /* vorspulen */
				goto conti;
			}
		}

		hl = hl_findheader( hlist, "U-Content-Transfer-Encoding" );
		if( hl && hl_findheader( hlist, "U-Mime-Version" ) )
		{
			if( !stricmp( hl->data, "quoted-printable" ) )
				isqp = TRUE;
		}

		hl = hl_findheader( hlist, "BET" );
		if( bigsort )
		{
			if(hl)
			{
				ogreSetStringValue( ogw, 4, hl->data );
			}
		}
		if( prefs.rfc_control_filter && hl )
		{
			if( !strncmp( hl->data, "cmsg cancel", 10 ) )
			{
				killcount++;
 				SeekAsync(f,maillen+currentcommentsize,MODE_CURRENT); /* vorspulen */
				goto conti;
			}
		}

		if( prefs.rfc_control_filter )
		{
			hl = hl_findheader( hlist, "U-CONTROL" );
			if( hl )
			{
				if( ( prefs.rfc_control_filter == 1 ) || !strnicmp( hl->data, "CANCEL", 6 ) )
				{
					killcount++;
	 				SeekAsync(f,maillen+currentcommentsize,MODE_CURRENT); /* vorspulen */
					goto conti;
				}
			}
		}

		hl = hl_findheader( hlist, "BEZ" );
		while(hl)
		{
			if(testidmke(hl->data))
			{
				hl2 = hl_findheader( hlist, "MID" );
				addmke(hl2->data);
				addmkemem(hl2->data);
				killcount++;
 				SeekAsync(f,maillen+currentcommentsize,MODE_CURRENT); /* vorspulen */
				goto conti;
			}
			hl = hl_findnextheader( hl );
		}

		/* Empfangsbestätigung */
		hl = hl_findheader( hlist, "STAT" );
		while(hl)
		{
			if(!stricmp(hl->data,"EB"))
			{
				gotebcount++;
				hl = hl_findlastheader( hlist, "BEZ" );
				if(hl)
				{
					if( markgoteb( hl->data, hlist ) )
					{
						int xxx;
		 				xxx = SeekAsync(f,maillen+currentcommentsize,MODE_CURRENT); /* vorspulen */
						goto conti;
					}
				}
				break;
			}
			hl=hl_findnextheader(hl);
		}

		/* Enthaelt die Nachricht einen Public-Key-Block? */
		if( pgpavail )
		{
			hl = hl_findheader( hlist, "PGP-PUBLIC-KEY" );
			if( hl )
			{
				hl2 = hl_findheader( hlist, "PGP-ID" );
				hl3 = hl_findheader( hlist, "ABS" );
				addpgpkey( hl, hl3, hl2 );
				pgpkeycount++;
			}
		}

		hl = hl_findheader( hlist, "CHARSET" );
		if( hl && !stricmp( hl->data, "ISO1" ) )
			isiso = TRUE;

		/* Nachricht MD-Codiert? */
		coded = FALSE;
		hl = hl_findheader( hlist, MDCRYPTHEADER );
		if( hl )
		{
			coded = TRUE;
			bin = FALSE;

			hl2 = hl_findheader( hlist, "TYP" );
			if( hl2 )
				hl_delheader( hl2 );

			/* Neuer Header? */
			if( hl->data[ 0 ] == 'M' )
			{
				stch_l( &hl->data[ 2 ], ( LONG *) &mailcode );
			}
			else
			{
				hl2 = hl_findheader( hlist, "MID" );
				strcpy( buffer, hl2->data );
				strupr( buffer );
				mailcode = crc32( buffer, strlen( buffer ) );
			}
		}

		/* Debug */
//		Printf( "Headerscan:\n" );
//		hl = hlist->l.mlh_Head;
//		while( hl->n.mln_Succ )
//		{
//			Printf( "%s:%s\n", hl->head, hl->data );
//			hl = hl->n.mln_Succ;
//		}

		/* Erstmal feststellen, ob eines der Empfängerbretter eingetragen ist */
		brettthere = 0;
		hl = hl_findheader( hlist, "EMP" );
		if( bigsort )
			ogreSetStringValue( ogw, 5, hl->data );
		ispm = FALSE;

		if( !hl )
			ispm = TRUE;

		while(hl)
		{
//			Printf( "PROCEMP %s\n", hl->data );

			p = hl->data;
			/* Kein Brett? */
			if( !p || ( p[0] != '/' ) )
			{
				ispm = TRUE;
				brettthere = 2;
				hl = hl_findnextheader( hl );
				continue;
			}
			mb = findbrett( p, 0 );
			if( mb )
			{
				brettthere = 1;
				break;
			}
			hl = hl_findnextheader( hl );
		}

		if( ispm && !hl_testheader( hlist, "CRYPT", "PGP" ) && !hl_testheader( hlist, "TYP", "BIN" ) && ( maillen + currentcommentsize ) )
		{
			int prepos = FtellAsync( f );
			char *p;
			int rc;

			rc = ReadAsync( f, buffer, min( 256, maillen + currentcommentsize ) );
			buffer[ rc ] = 0;

			if( strstr( buffer, "--BEGIN PGP MESSAGE--" ) )
				hl_addheader( hlist, "CRYPT", "PGP" );

			SeekAsync( f, prepos, OFFSET_BEGINNING );
		}
		if( hl_testheader( hlist, "CRYPT", "PGP" ) )
		{
			if( !pgpavail )
			{
				hl = hl_findheader( hlist, "MID" );
				hl2 = hl_findheader( hlist, "BET" );
				hl3 = hl_findheader( hlist, "ABS" );
				
				askreq( "PGP-verschlüsselte Nachricht\nMID: %s\nABS: %s\nBET: %s\nkonnte nicht entschlüsselt werden.\nBitte installieren Sie zuerst das PGP-Paket.", "Ignorieren",
					hl->data, hl3->data, hl2->data
				);
			}
			else
				pgpcrypt = TRUE;
		}

		if( sortpmsonly && ( brettthere != 2 ) )
		{
			SeekAsync(f,maillen+currentcommentsize,MODE_CURRENT); /* vorspulen */
			goto conti;
		}

		realmails++;

		if( prefs.do_packmsg )
			pix.flags |= PIF_PACKED;

		if( prefs.do_packmsg >= PACKMODE_XPK )
			pix.flags |= PIF_XPK;

		/* Gut, Nachricht kopieren */
		pix.offset = currentpufoffset;
		pix.headersize = hl_dumpheaderpf( hlist, destfile );

		if( isqp )
		{
			pix.datasize = copyqp( f, destfile, maillen );
		}
		else if( !pgpcrypt )
		{
resendnormal:
			if( currentcommentsize )
				pix.commentsize = copymailcomment( f, destfile, currentcommentsize, isiso );

			pix.datasize = copymsg( f, destfile, maillen, bin, coded, mailcode, isiso );
		}
		else
		{
			int oldmaillen = maillen;
			int oldcommentsize = currentcommentsize;
			// PGP-Nachricht entschlüsseln

			hl3 = hl_findheader( hlist, "CRYPT-CONTENT-KOM" );

			/* Evt. sonstigen Kommentar entsorgen */
			if( currentcommentsize )
				SeekAsync( f, currentcommentsize, OFFSET_CURRENT );

			if( hl3 )
			{
				currentcommentsize = atoi( hl3->data );
			}
			else
				currentcommentsize = 0;

			bin = hl_testheader( hlist, "CRYPT-CONTENT-TYP", NULL );

			/* Auslagern */
			copymsg2pgp( f, "T:mdtmp.pgp", maillen );

			DeleteFile( "T:mdtmp.txt" );
			rc = runpgp( "T:mdtmp.pgp -oT:mdtmp.txt", 1, 0 );
			if( rc > 1 || rc < 0 )
			{
				hl = hl_findheader( hlist, "MID" );
				hl2 = hl_findheader( hlist, "BET" );
				hl3 = hl_findheader( hlist, "ABS" );
				
				askreq( "PGP-verschlüsselte Nachricht\nMID: %s\nABS: %s\nBET: %s\nkonnte nicht entschlüsselt werden:\nPGP-Fehlercode %ld", "Normal speichern",
					hl->data, hl3->data, hl2->data, rc
				);
				SeekAsync( f, -( oldmaillen + oldcommentsize ), OFFSET_CURRENT );
				maillen = oldmaillen;
				currentcommentsize = oldcommentsize;
				goto resendnormal;
			}

			// Ok, in mdtmp.txt sollte nun das decryptete File stehen
			DeleteFile( "T:mdtmp.pgp" );

			strcpy( pgprealname, "T:mdtmp.txt" );
			maillen = getfilelen( "T:mdtmp.txt" );
			if( maillen < 0 )
			{
				if( bin )
					maillen = trypgp( "T:mdtmp.txt", pgprealname );
			}

			if( maillen < 0 )
			{
				hl = hl_findheader( hlist, "MID" );
				hl2 = hl_findheader( hlist, "BET" );
				hl3 = hl_findheader( hlist, "ABS" );
				askreq( "PGP-verschlüsselte Nachricht\nMID: %s\nABS: %s\nBET: %s\nkonnte nicht entschlüsselt werden:\nT:mdtmp.txt nicht gefunden.", "Normal speichern",
					hl->data, hl3->data, hl2->data
				);
				SeekAsync( f, -( oldmaillen + oldcommentsize ), OFFSET_CURRENT );
				maillen = oldmaillen;
				currentcommentsize = oldcommentsize;
				goto resendnormal;
			}

			maillen -= currentcommentsize;

			f2 = OpenAsync( pgprealname, MODE_READ, 8192 );

			if( currentcommentsize )
				pix.commentsize = copymailcomment( f2, destfile, currentcommentsize, isiso );

			//pix.datasize = copymsg( f2, destfile, maillen, bin, FALSE, 0, isiso );
			pix.datasize = copymsg( f2, destfile, maillen, TRUE, FALSE, 0, isiso );

			CloseAsync( f2 );
			DeleteFile( pgprealname );
		}

		currentpufoffset += ( pix.headersize + pix.commentsize + pix.datasize );
		WriteAsync( destix, &pix, sizeof( pix ) );

		/* Mail-Struktur basteln... */
		mail.pufferID = pufID;
		mail.mailID = mailID++;

		header2mail( hlist, &mail );

		hl = hl_findheader( hlist, "EMP" );
		while( hl )
		{
			sortedmails++;
			if( bigsort )
				ogreSetStringValue( ogw, 5, hl->data );
			p = hl->data;
			if( p[0] != '/' )
			{
				struct header *eb = hl_findheader( hlist, "EB");
				while(eb && ! ( prefs.ebmode & EBMODE_NEVER ) )
				{
					struct header *mid=hl_findheader( hlist, "MID");
					struct header *abs=hl_findheader( hlist, "ABS");
					struct header *bet=hl_findheader( hlist, "BET");
					struct header *rot=hl_findheader( hlist, "ROT");
					char ebtxt[1024],bettxt[128];
					int rc;

					if( prefs.ebmode & EBMODE_ASK )
					{
						rc = askreq( "Empfangsbestätigung verschicken?\n\nAbsender.: %s\nBetreff..: %s\nMsgId....: %s%s%s",
									"Ja|Nein",
									abs->data, bet->data,
									mid->data,
									( eb->data && eb->data[0] ) ? "\nEmpfänger: " : "",
									( eb->data && eb->data[0] ) ? eb->data : "" );
						if( !rc )
							goto conteb;
					}

					if( eb->data && eb->data[0] )
						abs = eb;

					sprintf(bettxt,"E:%-.124s",bet->data);
					sprintf(ebtxt,"Ihre Nachricht an \"%s\" (%s@%s%s)\nmit der Message-Id <%s>\nund dem Betreff \"%s\" ist über den Weg\n\"%s\" eingegangen.\n\nHinweis: Dies ist keine Bestätigung, ob oder wann die Nachricht gelesen\nwurde.\n",
						prefs.userrealname,
						prefs.username,
						( prefs.mode == MDM_RFC ) ? prefs.pointname : prefs.boxname,
						prefs.boxdomain,
						mid->data,
						bet->data,
						rot->data
					);
					sprintf(strchr(ebtxt,0),"\nYour message to \"%s\" (%s@%s%s)\nwith message-id <%s>\nand subject \"%s\" has been received successfully. Route: \n\"%s\"\n\nNote:This receipt doesn't imply that the message has been read.\n",
						prefs.userrealname,
						prefs.username,
						( prefs.mode == MDM_RFC ) ? prefs.pointname : prefs.boxname,
						prefs.boxdomain,
						mid->data,
						bet->data,
						rot->data
					);
					ebcount++;
					sendshortmail(
							abs->data,
							bettxt,
							ebtxt,
							mid->data, "STAT", "EB",
							prefs.pgp_sendoneb ? 2 : 0
					);
conteb:
					eb = hl_findnextheader( eb );
				}

				// Dasselbe mit PGP-Key-Requests

				if( pgpavail )
				{
					struct header *eb = hl_findheader( hlist, "PGP");
					while(eb && ( prefs.pgp_request != PGPR_IGNORE ) )
					{
						int rc;
						if( !stricmp( eb->data, "REQUEST" ) )
						{
							struct header *mid=hl_findheader( hlist, "MID");
							struct header *abs=hl_findheader( hlist, "ABS");
							struct header *bet=hl_findheader( hlist, "BET");
							if( prefs.pgp_request & PGPR_ASK )
							{
								rc = askreq( "Public-Key verschicken?\n\nAbsender.: %s\nBetreff..: %s\nMsgId....: %s",
									"Ja|Nein",
									abs->data, bet->data,
									mid->data );
								if( !rc )
									break;
							}
							sendpgpkey( abs->data );
							pgpkeysendcount++;
						}
						eb = hl_findnextheader( eb );
					}
				}
				pmcount++;
				p=0;
				mb = findpmbrett( hlist );
			}
			else
			{
				brettcount++;

				if( strchr( p, '@' ) )
				{
					strcpy( buffer, p );
					*strchr( buffer, '@' ) = 0;
					p = buffer;
				}

				mb=findbrett(p,(brettthere)?0:1);
			}
			if(!mb)
			{
				/* Brett gibbet nich */
				hl=hl_findnextheader(hl);
				continue;
			}
			mb->b.flags |= BFLAG_TOUCHED;

			if(!p)
			{
				struct header *abs=hl_findheader(hlist,"ABS");
				struct header *bet=hl_findheader(hlist,"BET");
				char cmpad[64];

				if( strchr( prefs.mapsoutname, '@' ) )
					strcpy( cmpad, prefs.mapsoutname );
				else
					sprintf( cmpad, "%s@%s", prefs.mapsoutname, prefs.boxname );
				if(abs && !strnicmp(abs->data,cmpad,strlen(cmpad)) && prefs.maps_listid[ 0 ] )
				{
					if( !strnicmp( bet->data, prefs.maps_listid, strlen( prefs.maps_listid ) ) )
					{
						foundblist = TRUE;
						mapsbl_pid = pufID;
						mapsbl_mid = mailID - 1;
					}
				}
			}

			storemail2ix( &mail, mb, NULL );

			hl = hl_findnextheader( hl );
		}

		/* excluden */

#if 0
		if( registerinfo.serie )
		{
			hl = hl_findheader( hlist, "X-MICRODOTUPDATE");
			if(hl && firstpath[0])
			{
				hl2 = hl_findheader( hlist, "ABS");
				if( hl2 && hl2->data )
				{
					strcpy( buffer, hl2->data );
					strlwr( buffer );
					if( crc32( buffer, strlen( buffer )) == 0x9e6ee29f)
					{
						mdk_pid = pufID;
						mdk_mid = mailID -1 ;
						foundupdate = 1;
					}
				}
			}
		}
		else
		{
			hl = hl_findheader( hlist, "X-MICRODOTKEY" );
			if(hl && firstpath[0])
			{
				hl2 = hl_findheader( hlist, "ABS" );
				if( hl2 && hl2->data )
				{
					strcpy(buffer,hl2->data);
					strlwr(buffer);
					if( crc32( buffer, strlen( buffer )) == 0x9e6ee29f)
					{
						mdk_pid = pufID;
						mdk_mid = mailID - 1;
						foundupdate = 2;
					}
				}
			}
		}
#endif

conti:
		/*filepos = FtellAsync(f);*/
		filepos += ( currentheadersize + maillen ); 

		ogreSetValue( ogw, 7, filepos );

		sprintf(buff,"%lD PM, %lD Brett, %lD Kill, %lD/%lD EB",pmcount,brettcount,killcount,gotebcount,ebcount);
		ogreSetStringValue( ogw, 2, buff );

		hl_freeheader( hlist );
		hlist = NULL;

		if( ! ( realmails & 15 ) )
			doinfofg();

	}
xit:

	CloseAsync( f );
	CloseAsync( destfile );
	CloseAsync( destix );

	hl_freeheader( hlist );

	freeinfofg();

	stime = time(0) - stime;
	if(!stime) stime = 1;
	printlog("Benötigte Zeit....: %02ld:%02ld:%02ld (%lD KByte/sec)\n",TH(stime),TM(stime),TS(stime),((filelen+1023)/1024)/stime);
	if(filelen) printlog("Headeranteil......: %lD Bytes (%ld%%)\n",headersize,(headersize*100)/filelen);
	printlog("Persönliche Mails.: %lD\n",pmcount);
	printlog("Brettnachrichten..: %lD\n",brettcount);
	printlog("Gekillt...........: %lD\n",killcount);
	printlog("EBs erhalten......: %lD\n",gotebcount);
	printlog("EBs verschickt....: %lD\n",ebcount);
	if( pgpavail )
	{
		printlog("Neue PGP-Keys.....: %lD\n", pgpkeycount );
		printlog("Verschickte Keys..: %lD\n", pgpkeysendcount );
	}
	if( realmails )
		printlog("Crosspostinganteil: %ld%% (%lD Nachrichten, %lD Empfänger)\n",
			100 - PERC( realmails, sortedmails ),
			realmails,
			sortedmails
		);
/*	reportmailercounter( realmails );*/

	printlog("\n");

	if(foundblist)
	{
		struct msghandle *msg = msg_open( mapsbl_pid, mapsbl_mid );
		if( msg )
		{
			pushhomedir();
			msg_copy( msg, "microdot.mapsblist", MC_DATA );
			msg_close( msg );
			printlog("Brettliste von MAPS empfangen und extrahiert.\n\n");
			popdir();
		}
	}
#if 0
	if( foundupdate )
	{
		struct msghandle *msg = msg_open( mdk_pid, mdk_mid );
		struct hlist *hlist;
		struct header *hl;
		if( msg )
		{
			pushhomedir();
			DeleteFile( "microdot.__temp ");
			msg_copy( msg, "microdot.__temp", MC_DATA );
			hlist = msg_loadheader( msg );
			msg_close( msg );

			if( foundupdate == 2 )
			{
				hl = hl_findheader( hlist, "X-MICRODOTKEY" );
				doextractkey( "microdot.__temp", hl->data );
			}
			else
			{
				hl = hl_findheader( hlist, "X-MICRODOTUPDATE" );
				doextractupdate( "microdot.__temp", hl->data );

			}
			hl_freeheader( hlist );
			DeleteFile( "microdot.__temp ");
			popdir();
		}
	}
#endif

	if( realmails )
	{
		printlog( "Neue Nachrichten aufgeteilt nach Brettern:\n------------------------------------------#-------\n" );
		dumpmbrettnmcounter();
		printlog( "\n" );
	}

	resetmbrettnmcounter();

	DeleteFile( "T:mdtmp.txt" );
	DeleteFile( "T:mdtmp.pgp" );

	if( !dontclosesortinwin )
	{
		ogreExitWindow( ogw );
		ogw = NULL;
	}

	return(rc);
}

static void breakmid( char *m )
{
	char *oldmp = m;

	m = strchr( m, '<' );
	if( !m )
		return;

	m = stpblk( ++m );
	strcpy( oldmp, m );

	m = strchr( oldmp, '>' );

	if( m )
		*m = 0;
}

static char *zc2z38( char *fromname )
{
	static char newn[32];
	char buffer[1024];
	FILE *inf, *outf;
	int inlen;
	char emp[128];
	char bet[128];
	char abs[256];
	char dat[128];
	char rot[256];
	char mid[256];
	char typ[64];
	char len[64];
	char *p;
	int ml;
	int rp;
	int c;
	struct ogwin *ogw;
	/*struct Window *w;*/

	inlen = getfilelen( fromname );
	inf = fopen( fromname, "r" );
	if( !inf )
		return( NULL );

	sprintf( newn, "._.Z%lx", time( 0 ) );
	outf = fopen( newn, "w" );
	if( !outf )
	{
		fclose( inf );
		return( NULL );
	}

	fsetbuf( inf, 16384 );
	fsetbuf( outf, 16384 );

	ogw = ogreInitWindow( scr, WFLG_RMBTRAP, NULL, "Konvertiere Z38-Puffer" );

	ogreAddGroup( ogw, 0, OGFRAME_NONE, NULL );
	ogreAddText( ogw, 0, " Von:", 0, fromname , 42, TRUE );
	ogreAddText( ogw, 1, "Nach:", 1, newn, 42, TRUE );
	ogreAddFuelGauge( ogw, 2, 2, inlen );
	ogreOpenWindow( ogw );

	for( ;; )
	{
		ogreSetValue( ogw, 2, ftell( inf ) );

		if( !fgets( emp, 127, inf ) )
			break;
		if( !fgets( bet, 127, inf ) )
			break;
		if( !fgets( abs, 127, inf ) )
			break;
		if( !fgets( dat, 127, inf ) )
			break;
		if( !fgets( rot, 255, inf ) )
			break;
		if( !fgets( mid, 255, inf ) )
			break;
		if( !fgets( typ, 63, inf ) )
			break;
		if( !fgets( len, 63, inf ) )
			break;

		ml = atoi( len );

		/* Nach im Z-38-Text versteckten Headern suchen */
		if( typ[0] == 'T' && ml )
		{
			rp = ftell( inf );
			for( c = 0; c < 3; c++ )
			{
				if( !fgets( buffer, 1023, inf ) )
					break;
				clnl( buffer );
				p = strchr( buffer, ':' );
				if( !p )
					break;
				*p++ = 0;
				p = stpblk( p );

				/* In buffer steht header, in p data */
				if( !stricmp( buffer, "message-id" ) )
				{
					breakmid( p );
					sprintf( mid, "%s\n", p );
				}
				else if( !stricmp( buffer, "references" ) )
				{
					breakmid( p );
					fprintf( outf, "BEZ:%s\n", p );
				}
				else if( !stricmp( buffer, "mailer" ) )
				{
					fprintf( outf, "MAILER:%s\n", p );
				}
				else if( !stricmp( buffer, "realname" ) )
				{
					asprintf( abs, " (%s)", p );
				}
			}
			fseek( inf, rp, 0 );
		}

		fprintf( outf, "EMP:%s", emp );
		if( bet[0] == '#' )
		{
			fprintf( outf, "EB:\r\n" );
			strcpy( &bet[0], &bet[1] );
		}

#if 0
		if( !strnicmp( bet, "XMD:", 4 ) && 
		  ( !strnicmp( abs, "e.lUNDqUIsT@AWOrLD.zer", 22 ) ) || !strnicmp( abs, "e.lundquiSt%AWORLD", 18 ) ) 
		{
			strcpy( abs, "e.lundquist@aworld.aworld.de (Erhard Lundquist)\n" );

			if( bet[4] == 'K' && emp[0] != '/' )
				fprintf( outf, "X-MICRODOTKEY:%s", &bet[5] );
			else if( bet[4] == 'U' )
				fprintf( outf, "X-MICRODOTUPDATE:%s", &bet[5] );
		}
#endif

		fprintf( outf, "BET:%sMID:%sABS:%sROT:%s", bet, mid, abs, rot );
		clnl( dat );
		fprintf( outf, "EDA:19%s00W+1\n", dat );
		if( typ[0] != 'T')
			fprintf( outf, "TYP:BIN\n");

		fprintf( outf, "LEN:%ld\n\n", ml );

		if( ml )
			copyff( inf, outf, ml );

	}

	fclose( inf );
	fclose( outf );

	ogreExitWindow( ogw );

	return( newn );
}


int sortinfile( char *name )
{
	int rc = 0;

	execrexx( "SortinExit" );

	/* Zuerst nach Z38 wandeln */
	if( ISN38 )
	{
		name = zc2z38( name );

		if( name )
		{
			rc = sortinfile2( name );
			DeleteFile( name );
		}

		return( rc );
	}

	if( name )
	{
		extern void execrexxargswait( char*,char*,int );

		execrexxargswait( "ProcessFile", name, TRUE );
		rc = sortinfile2( name );
	}
	return( rc );
}

extern int backdisable;

void sortinarchive( char *name )
{
	int rc;
	char buff[ 4096 ],
		 *p,
		 pat[256];
	int abort = FALSE;

	rc = askreq( "Die Datei\n%s\nist kein Netcall-Puffer, sondern wahrscheinlich\nein Archiv mit mehreren Netcall-Puffern.\nSoll das Archiv automatisch entpackt und die darin\nenthaltenen Dateien einsortiert werden?",
		"Entpacken und Einsortieren|Datei ignorieren",
		name );
	if( !rc  )
		return;

	/* Archiv kopieren */
	strcpy( pat, prefs.transferdir );
	addpart( pat, "sortin_archiv.LZH" );

	if( copyfile( name, pat ) )
	{
		askreq( "Fehler beim Kopieren von\n%s nach %s", "Abbruch",
			name, pat );
		return;
	}

	setgotfilename( "sortin_archiv.LZH" );

	backdisable = TRUE;
	if( unpackdata() )
	{
		backdisable = FALSE;
		DeleteFile( pat );
		return;
	}

	DeleteFile( pat );

	loadmke();
	loaduk();

	while( !abort )
	{
		rc = makefilelist( prefs.transferdir, "#?", buff, 4096 );
		if( rc < 1 )
			break;
		p=buff;
		while( rc-- > 0 )
		{
			if( strnicmp( p, "BAD-XFER", 8 ) )
			{
				pushdir( prefs.transferdir );
				if( sortinfile( p ) == -1 )
				{
					abort = TRUE;
					break;
				}
				DeleteFile( p );
				popdir();
			}
			p=strchr( p, 0 );
			p++;
		}
	}

	freemke();
	freeuk();
	closeallixfiles();
}


void sortinhand(void)
{
	struct rtFileList *fl,*it;
	char filename[256];
	BPTR f;
	char testbuff[ 256 ];
	UBYTE *p1;
	int found;
	int rc;

	if( prefs.mode == MDM_RFC )
	{
		dosortin();
		return;
	}

	filename[0]=0;
	fl=rtFileRequest(fr[FR_SORTIN],filename,"Dateien einsortieren...",
		RT_Screen,scr,RT_ReqPos,REQPOS_CENTERSCR,
		RTFI_Flags,FREQF_MULTISELECT,
		TAG_DONE);
	if(!fl) return;

	it=fl;

	sprintf(filename,"Sortinprotokoll %s",dat2str(time(0)));
	openlogmsg(filename);

	dontclosesortinwin = TRUE;

	while(it)
	{
		strcpy(filename,fr[FR_SORTIN]->Dir);
		addpart(filename,it->Name);

		/* Gut, in Filename steht der Name. Gucken ob Puffer */
		memset( testbuff, 0, 256 );
		f = Open( filename, MODE_OLDFILE );
		if( !f )
		{
			displaybeep();
			nofilereq( filename, IoErr() );
			break;
		}
		Read( f, testbuff, 255 );
		Close( f );
		clnl( testbuff );
		p1 = testbuff;
		found = ISN38;
		while( ( ( *p1 > 31 ) || ( *p1 == 9 ) ) && ( *p1 != 127 ) )
		{
			if( *p1++ == ':' )
				found = 1;
		}

		/* Falls Stringende und ':', ist es ein Puffer */

		if( !*p1 && found )
		{
			loadmke();
			loaduk();
			rc = sortinfile(filename);
			freemke();
			freeuk();
			if( rc == -1 )
				break;
		}
		else /* Wohl ein Archiv... */
		{
			sortinarchive( filename );		
		}

		it=it->Next;
	}
	savebretter();
	closelogmsg();

	rtFreeFileList(fl);
	closeallixfiles();

	dontclosesortinwin = FALSE;
	if( ogw )
	{
		ogreExitWindow( ogw );
		ogw = NULL;
	}
}

void dosortin( void )
{
	int rc;
	char buff[ 8192 ],
		 *p;
	int abort = FALSE;

	sprintf( buff, "Sortin %s", dat2str( time(0) ) );
	openlogmsg( buff );

#ifndef NO_RFC
	if( prefs.mode == MDM_RFC )
	{
		printlog( "Konvertierung der eingegangenen Daten:\n\n" );
		convrfc();
		printlog( "\n" );
		//printlog( "\nEinsortieren:" );
	}
#endif

	loadmke();
	loaduk();
	pushdir( prefs.transferdir );

	dontclosesortinwin = TRUE;

	while( !abort )
	{
		rc = makefilelist( "", prefs.mode == MDM_RFC ? "Sortin.#?" : "#?", buff, 8192 );
		if( rc < 1 )
			break;
		p = buff;
		while( rc-- )
		{
			if( strnicmp( p, "BAD-XFER", 8 ) )
			{
				if( sortinfile( p ) == -1 )
				{
					abort = TRUE;
					break;
				}
				DeleteFile( p );
			}
			p=strchr( p, 0 ) + 1;
		}
	}
	popdir();
	closelogmsg();
	savebretter();
	closeallixfiles();
	freemke();
	freeuk();

	dontclosesortinwin = FALSE;
	if( ogw )
	{
		ogreExitWindow( ogw );
		ogw = NULL;
	}
}

#if 0
static void makerlinks(struct mindex *mix)
{
	struct mmail *current;
	struct mmail *bez,*firstbez,*p;

 	current=(struct mmail*)mix->maillist.lh_Head;
	while(current->n.mln_Succ)
	{
		current->parent = NULL;
		current->bezlink = NULL;
		current->firstbez = NULL;
		current=(struct mmail*)current->n.mln_Succ;
	}

 	current=(struct mmail*)mix->maillist.lh_Head;
	while( current->n.mln_Succ )
	{
		/* Alle Replies auf diese Mail linken */
		firstbez = NULL;
		bez = ( struct mmail * ) mix->maillist.lh_Head;
		//bez = ( struct mmail * ) current->n.mln_Succ;
		while( bez->n.mln_Succ )
		{
			if( !bez->parent && ( bez->m.bezcrc == current->m.midcrc ) )
			{
				if( !firstbez )
				{
					current->firstbez = bez;
				}
				else
				{
					firstbez->bezlink = bez;
				}
				firstbez = bez;
				bez->parent = current;
			}
			bez = ( struct mmail * ) bez->n.mln_Succ;
		}
		current = ( struct mmail * ) current->n.mln_Succ;
	}
}
#endif

extern void __asm makerlinks( register __a0 APTR );

static struct mindex *findmemmix( struct mbrett *mb )
{
	struct mindex *mix;

	SaveNewList( &mixlist );
	mix = ( struct mindex * ) mixlist.mlh_Head;
	while( mix->n.mln_Succ )
	{
		if( mix->mb == mb )
			return( mix );
		mix = ( struct mindex * ) mix->n.mln_Succ;
	}
	return( NULL );
}

struct mindex *loadbrettixquiet(struct mbrett *mb)
{
	int c;
	struct AsyncFile *bf;
	struct mindex *mix;
	struct mmail *mm;
	void *mempool;

	Forbid();
	SaveNewList( &mixlist );
	mix = findmemmix( mb );
	if( mix )
	{
		mix->usecount++;
		//makerlinks( mix );
		Permit();
		return( mix );
	}
	Permit();

	mempool = LibCreatePool( MEMF_CLEAR, sizeof( *mm ) * 64 , sizeof( *mm ) * 8 );
	if( !mempool )
		return( NULL );
	mix = LibAllocPooled(mempool,sizeof(struct mindex));
	if( !mix )
		return( 0 );
	mix->mempool = mempool;
	mix->usecount = 1;
	NewList( &mix->maillist );
	Forbid();
	AddTail( ( struct List * ) &mixlist, ( struct Node * ) mix );
	Permit();
	mix->mb = mb;

	mb->b.flags &= ~BFLAG_TOUCHED;

	bf = getixfile( mb, MODE_READ );

	if( !bf )
	{
		return( mix );
	}

	for(c=0; ; c++, mix->mailcount++ )
	{
		mm=LibAllocPooled(mix->mempool,sizeof(struct mmail));
		if(!mm)
		{
			Remove( mix );
			LibDeletePool( mix->mempool );
			displaybeep();
			askreq( "Kein Speicher für Index von Brett\n\"%s\".", "Abbruch", mb->b.name );
			return( NULL );
		}
		if( ReadAsync(bf,&mm->m,sizeof(struct mail)) < sizeof( struct mail ) )
			break;
		AddTail(&mix->maillist,(struct Node*)mm);
	}

//	Printf( "read %ld entries\n", c );

	return(mix);
}

struct mindex *loadbrettix(struct mbrett *mb)
{
	struct mindex *mix = loadbrettixquiet( mb );
	if( mix )
	{
		if( mix->changed || !mix->rlinks )
		{
			makerlinks( mix );
			mix->rlinks = TRUE;
		}
	}
	return( mix );
}

void freebrettix( struct mindex *mix )
{
	if( mix )
	{
		if( ! ( --mix->usecount ) )
		{
			/* Falls unter V39, sofort freigeben */
			if( !isv39 || prefs.noixcache )
			{
				Remove( mix );
				/* Pool löschen */
				LibDeletePool( mix->mempool );
			}
		}
	}
}

void flushbrettix( void )
{
	struct mindex *mix;
	struct Node *n;
	struct List templist;

	NewList( &templist );

	SaveNewList( &mixlist );
	while( ( mix = ( struct mindex * ) RemHead( &mixlist ) ) )
	{
		if( mix->usecount )
			AddTail( &templist, mix );
		else
			LibDeletePool( mix->mempool );
	}

	while( ( n = RemHead( &templist ) ) )
		AddTail( &mixlist, n );
}

void flushbrettixall( void )
{
	struct mindex *mix;

	SaveNewList( &mixlist );
	while( ( mix = ( struct mindex * ) RemHead( &mixlist ) ) )
		LibDeletePool( mix->mempool );
}


int savebrettix(struct mindex *mix,struct mbrett *mb)
{
	struct AsyncFile *f;
	int c;
	struct mmail *mm;
	int newcount=0,mailcount=0,unreadcount=0;

	if( !mix->changed )
		return(0);

	f = getixfile( mb, MODE_WRITE );
	if( !f )
	{
//		Printf( "!!!openerror!\n" );
		return( IoErr() );
	}
	mm=(struct mmail*)mix->maillist.lh_Head;
	for(c=0; mm->n.mln_Succ; c++,mm=(struct mmail*)mm->n.mln_Succ)
	{
		if( ! ( mm->m.flags & MMF_KILL ) )
		{
			mailcount++;
			if(mm->m.flags&(MMF_UNSEEN|MMF_SHOW)) newcount++;
			if(!(mm->m.flags&MMF_READ)) unreadcount++;
			WriteAsync(f,&mm->m,sizeof(struct mail));
		}
	}
	mix->changed		= 0;
	mix->rlinks			= 0;
	mb->b.mails			= mailcount;
	mb->b.newmails		= newcount;
	mb->b.unreadmails	= unreadcount;

	closeixfile( mb );

	return(0);
}

/* Mail speichern; falls einer der Indizes geladen ist, entsprechend
   updaten */

void __stdargs storemail2ix( struct mail *m, struct mbrett *dest, ... )
{
	struct mbrett **mbp = &dest;
	struct AsyncFile *f;
	struct mindex *mix;
	struct mmail *mm;

	while( *mbp )
	{
		(*mbp)->b.mails++;
		(*mbp)->b.newmails++;
		(*mbp)->b.unreadmails++;
		(*mbp)->newmails++;

		time( &(*mbp)->b.lastwrite );
		makembrettlastwrite( *mbp );

		f = getixfile( *mbp, MODE_APPEND );
		if( f )
			WriteAsync( f, m, sizeof( *m ) );

		Forbid();
		mix = findmemmix( *mbp );
		if( mix )
		{
			mix->usecount++;
			mm = LibAllocPooled(mix->mempool,sizeof(struct mmail));
			if( mm )
			{
				mm->m = *m;
				AddTail( &mix->maillist, ( struct Node * ) mm );
				/*makerlinks( mix );*/
				mix->changed = 1;
				mix->mailcount++;
			}
			mix->usecount--;
		}
		mbp++;
		Permit();
	}
}
