#include "microdot.h"

#include <dos/dostags.h>
#include <proto/datatypes.h>
#include <proto/whatis.h>
#include <datatypes/datatypesclass.h>

#include "ogre.h"
#include "ogre_protos.h"

static struct List mlist;
static USHORT usecmpid;
static ULONG cmpid;
struct mbrett *cmb;
struct mindex *mix;

long mmcount;
USHORT wrotenewmails, oldbrettmaxnum;
static int lastmailnum;
int donextnewboard;
static struct mmail *newmailptr;

static struct vmail *currentreadermail;

extern BOOL didsortin;

void *mlistpool;

#define TCONV (char*)1

static char *skipre( char *txt );

static char *headertab[]={
	"EMP",			"Empfänger", 		FALSE,
	"ABS",			"Absender",			FALSE,
	"ROT",			"Routweg",			FALSE,
	"LEN",			"Länge",			FALSE,
	"BET",			"Betreff",			FALSE,
	"PRIO",			"Priorität",		FALSE,
	"MID",			"Message-ID",		FALSE,
	"BEZ",			"Bezugs-ID",		FALSE,
	"ZNETZ-CONV",	"Z38-Converter",	FALSE,
	"ANTWORT-AN",	"Antwort an",		FALSE,
	"DISKUSSION-IN","Diskussion in",	FALSE,
	"MAILER",		"Mailer",			FALSE,
	"WAB",			"W-Absender",		FALSE,
	"O-ROT",		"O-Routweg",		FALSE,
	"OAB",			"O-Absender",		FALSE,
	"OEM",			"O-Empfänger",		FALSE,
	"ORG",			"Organisation",		FALSE,
	"FILE",			"Dateiname",		FALSE,
	"TELEFON",		"Telefonnummer",	FALSE,
	"POST",			"Postanschrift",	FALSE,

	"EDA",			"Datum",			TCONV,
	"SPERRFRIST",	"Sperrfrist",		TCONV,
	"LDA",			"Löschdatum",		TCONV,
	"DDA",			"Dateidatum",		TCONV,
	"VIA",			"Via Routesystem",	TCONV,
	0
};

static char datmem[ 256 ];
static char *translateheader( char *head, char *data )
{
	char **p = headertab;

	datmem[0] = 0;
	while( p[0] )
	{
		if( !stricmp( head, p[0] ) )
		{
			/* Datumskonvertierung */
			if( p[2] && data )
			{
				char tmpdata[ 64 ];

				strncpy( tmpdata, data, 64 );
				tmpdata[ 63 ] = 0;
				while( strlen( tmpdata ) < 20 ) 
					strcat( tmpdata, " " );

				sprintf( datmem, "%.2s.%.2s.%.4s %.2s:%.2s:%.2s (%3.3s) %s",
					&tmpdata[6],&tmpdata[4],tmpdata,
					&tmpdata[8],&tmpdata[10],&tmpdata[12],
					&tmpdata[ 14 ],
					&tmpdata[ 17 ]
				);
			}
			return( p[1] );
		}
		p++;
		p++;
		p++;
	}
	return( head );
}

static void freemlist(void)
{
	if( mlistpool )
	{
		LibDeletePool( mlistpool );
		mlistpool = 0;
	}
}

struct msghandle *msg_openv( struct vmail *n )
{
	struct msghandle *msg;

	if( !n )
	{
		displaybeep();
		return( NULL );
	}

	msg = msg_open( n->m->m.pufferID, n->m->m.mailID );

	if( !msg )
		displaybeep();

	return( msg );
}


void calcmcount(void)
{
	struct vmail *mm=(struct vmail*)mlist.lh_Head;
	long newcount=0,delcount=0,mailcount=0,foldcount=0,unreadcount=0;
	char buffer[128];

	mmcount=0;
	while( mm->n.mln_Succ )
	{
		if( ! ( mm->m->m.flags & MMF_KILL ) )
		{
			mailcount++;
			if(mm->sel) mmcount++;
			if(mm->m->m.flags & MMF_DEL ) delcount++;
			if(mm->m->m.flags & MMF_FOLD) foldcount++;
			if(mm->m->m.flags & (MMF_UNSEEN|MMF_SHOW)) newcount++;
			if(!(mm->m->m.flags & MMF_READ)) unreadcount++;
		}
		mm=(struct vmail*)mm->n.mln_Succ;
	}
	cmb->b.mails=mailcount;
	cmb->b.newmails=newcount;
	cmb->b.unreadmails=unreadcount;

	sprintf(buffer,"%lD Nachrichten, %lD neu, %lD ungelesen, %lD gelöscht",mailcount,newcount,unreadcount,delcount);
	if(mmcount)
	{
		asprintf(buffer,", %lD markiert",mmcount);
	}
	if(foldcount)
	{
		asprintf(buffer,", %lD gefaltet",foldcount);
	}
	
	preport(1,1,buffer);

	if(cmb->b.betreff[0])
		preport(0,1,"NACHRICHTENAUSWAHL: Brett %s (%s)",cmb->b.name,cmb->b.betreff);
	else
		preport(0,1,"NACHRICHTENAUSWAHL: Brett %s",cmb->b.name);
}

/*
 *  Markierungen speichern
 */

void savesel( void )
{
	struct vmail *mm=(struct vmail*)mlist.lh_Head;

	while( mm->n.mln_Succ )
	{
		mm->savedsel = mm->sel;
		mm=(struct vmail*)mm->n.mln_Succ;
	}

}

/*
 *  Markierungen wiederherstellen
 */

static void restoresel( void )
{
	struct vmail *mm=(struct vmail*)mlist.lh_Head;

	while( mm->n.mln_Succ )
	{
		mm->sel = mm->savedsel;
		mm=(struct vmail*)mm->n.mln_Succ;
	}

}


#if 0
static void makemmailhash( struct mmail *m )
{
	char *p = skipre( m->m.betreff );

	m->hash_bet =	( tolower( p[ 0 ] ) << 24 ) +
					( tolower( p[ 1 ] ) << 16 ) +
					( tolower( p[ 2 ] ) << 8 ) +
					( tolower( p[ 3 ] ) );

//	Printf( "hash %s %lx\n", p, m->hash_bet smake);
}
#endif


static struct vmail *findvmail(struct mmail *m)
{
	struct vmail *vm=(struct vmail*)mlist.lh_Head;

	while(vm->n.mln_Succ)
	{
		if(vm->m==m) return(vm);
		vm=(struct vmail*)vm->n.mln_Succ;
	}
	return(0);
}

static struct vmail *findparentmail( struct vmail *vm )
{
	struct mmail *m;

	if( !vm )
		return( NULL );

 	m = vm->m;

	while( m->parent )
		m = m->parent;

	vm = findvmail( m );
	return( vm );
}

static void resendmail( struct vmail *n )
{
	struct msghandle *msg;
	struct hlist *hlist;
	struct header *abs, *emp, *bet;
	struct mbrett *sp=findbrett("/»SPOOL",0);
	struct mail tmp;

	msg = msg_openv( n );
	if( !msg )
		return;
	hlist = msg_loadheader( msg );
	msg_close( msg );
	if( !hlist )
	{
		return;
	}

	abs = hl_findheader( hlist, "ABS" );
	emp = hl_findheader( hlist, "EMP" );
	bet = hl_findheader( hlist, "BET" );

	if( abs )
	{
		askreq( "Fehler: Sie können nur Ihre eigenen\nNachrichten erneut verschicken.", "Abbruch" );
		hl_freeheader( hlist );
		return;
	}
	if( !askreq( "Wollen Sie Ihre Nachricht\nmit BET: %s\nund EMP: %s\nerneut verschicken?", "Verschicken|Abbruch",
		bet->data, emp->data ) )
	{
		hl_freeheader( hlist );
		return;
	}
	hl_freeheader( hlist );

	tmp = n->m->m;
	tmp.flags &= ~(MMF_ARCHIVE|MMF_DEL);
	storemail2ix( &tmp, sp, NULL );
}

static char *getcookie( struct mbrett * cmb )
{
	static char buffer[ 1024 ];
	int counter=0;
	char b2[128];
	FILE *f;

	strcpy( buffer, "microdot.cookies" );
	if( cmb && cmb->b.language )
		asprintf( buffer, ".%ld", cmb->b.language );

	f = fopen( buffer, "r" );
	if( !f )
		return( "" );

	fsetbuf( f, 8192 );

	while( ( fgets( buffer, 128, f ) ) )
	{
		clnl( buffer );
		if( !buffer[0] )
			counter++;
	}
	fseek( f, 0, 0 );
	if( counter )
		counter = ( prefs.counter++ ) % counter;
	while( counter && ( fgets( buffer, 256, f ) ) )
	{
		clnl( buffer );
		if( !buffer[ 0 ] )
			counter--;
	}
	buffer[ 0 ] = 0;
	while( ( fgets( b2, 128, f ) ) )
	{
		clnl( b2 );
		if( !b2[ 0 ] )
			break;
		
		if( strlen( buffer ) + strlen( b2 ) > 1021 )
			break;

		asprintf( buffer, "%s\n", b2 );
	}
	fclose(f);
	if( buffer[ 0 ] )
		buffer[ strlen( buffer ) - 1 ] = 0;
	return( buffer );
}

void doorigin(FILE *f,int public,struct mbrett *cmb)
{
	char *p;
	int c,ch;
	FILE *f2;
	char buffer[256];

	p=(public)?"md_orig.pub":"md_orig.priv";

	strcpy( buffer, p );
	if( cmb && cmb->b.language )
		asprintf( buffer, ".%ld", cmb->b.language );
	p = buffer;

	if( cmb )
	{
		if(cmb->b.flags&BFLAG_NOORIGIN) p=0;
		if(cmb->b.flags&BFLAG_SPECIALORIGIN)
		{
			brettpfad(buffer,cmb);
			addpart(buffer,".Origin");
			p=buffer;
		}
	}

	if(p)
	{
		c=getfilelen(p);
		if(c>2) {
			f2=fopen(p,"r");
			fsetbuf(f2,2048);
			/*fprintf(f,"\n\n\n\n");*/
			for(;;)
			{
				ch=fgetc(f2);
				if(ch<0) break;
				if(ch=='$')
				{
					for( c = 0; c < 16; c++ )
					{
						ch = fgetc( f2 );
						if( ch == EOF || ch == '$' )
							break;
						buffer[c] = ch;
					}
					buffer[c] = 0;

					if( !stricmp( buffer, "cookie" ) )
						fputs( getcookie( cmb ), f );
					else if( !stricmp( buffer, "ver" ) )
						fputs( "MicroDot V" MDVER, f );
					else
						fputc( '$', f );
				}
				else fputc(ch,f);
			}
			fclose(f2);
		}
	}

}

static struct vmail *findnextunread(struct vmail *vm)
{
	struct vmail *mm;

	if( !vm )
		return( NULL );
	vm= (struct vmail *) vm->n.mln_Succ;
	if( !vm )
		return( NULL );
	while( ( mm= (struct vmail*) vm->n.mln_Succ ) )
	{
		if( !( vm->m->m.flags & MMF_READ ) )
			break;
		vm = mm;
	}
	return( ( mm ) ? vm : NULL);
}

static void checksignature(struct vmail *n)
{
	struct header *hl, *hl2;
	struct msghandle *msg;
	struct hlist *hlist;
	BPTR f;
	char signature[ 1024 ];
	int siglen, isbin;

	if( n->m->m.flags & MMF_PGPSIGNED )
	{
		if( !askreq( "Die Signatur dieser Nachricht\nist bereits geprüft und\nfür korrekt befunden worden.", "Trotzem prüfen|Abbruch" ) )
			return;
	}

	DeleteFile( "T:mdpgp.iso" );
	DeleteFile( "T:mdpgp.txt" );

	msg = msg_open( n->m->m.pufferID, n->m->m.mailID );
	if( !msg )
	{
		displaybeep();
		return;
	}

	/* Emps suchen */
	hlist = msg_loadheader( msg );

	isbin = hl_testheader( hlist, "TYP", 0 );

	hl = hl_findheader( hlist, "SIGNED" );
	while( hl )
	{
		if( !stricmp( hl->data, "PGP" ) )
			break;
		hl = hl_findnextheader(hl);
	}

	//
	//	Keine Signatur gefunden
	//

	hl2 = hl_findheader( hlist, "PGP-SIG" );

	if( !hl || !hl2 )
	{
		hl_freeheader( hlist );
		msg_close( msg );
		askreq( "Diese Nachricht enthält keine PGP-Signatur.", "Abbruch" );
		return;
	}

	if( dpem_buffer( hl2->data, signature, &siglen ) )
	{
		hl_freeheader( hlist );
		msg_close( msg );
		askreq( "Die Signatur dieser Nachricht\nist offenbar zerstört.", "Abbruch" );
		return;
	}

	f = Open( "T:mdpgp.sig", MODE_NEWFILE );
	Write( f, signature, siglen );
	Close( f );

	if( isbin )
	{
		msg_copy( msg, "T:mdpgp.iso", MC_COMMENT );
		convpgpmsg();
		DeleteFile( "T:mdpgp.iso" );
		f = Open( "T:mdpgp.txt", MODE_READWRITE );
		Seek( f, 0, OFFSET_END );
		msg_copyfh( msg, f, MC_DATA );
		Close( f );
	}
	else
	{
		msg_copy( msg, "T:mdpgp.iso", MC_DATA | MC_COMMENT );
		convpgpmsg();
		DeleteFile( "T:mdpgp.iso" );
	}

	msg_close( msg );

	if( !runpgp( "T:mdpgp.sig T:mdpgp.txt", 0, 1 ) )
	{
		n->m->m.flags |= MMF_PGPSIGNED;
		mix->changed = 1;
	}

	hl_freeheader( hlist );

	DeleteFile( "T:mdpgp.sig" );
	DeleteFile( "T:mdpgp.txt" );
}

static void iteratemsglist( void (*func)( struct vmail * ) )
{
	struct vmail *n = ( struct vmail * ) mlist.lh_Head;

	mix->changed=1;

	if(!mmcount)
	{
		n=(struct vmail*)GetEntry(&mlist,getscrollercurrent());
		if( n )
			func( n );
	}
	else
	{
		savesel();
		while( n->n.mln_Succ )
		{
			if( n->sel )
			{
				func( n );
				n->sel = 0;
			}
			n=(struct vmail*)n->n.mln_Succ;
		}
	}
}

static void checksignatures( void )
{
	iteratemsglist( checksignature );
}

static int doweitermail(struct vmail *n)
{
	char buffer[256],bet[256],comment[256];
	long empcount=0;
	char **emplist;
	void *rkey;
	struct header *hl;
	int rc;
	struct msghandle *msg;
	struct hlist *hlist;

	DeleteFile( TMPMSGNAME );
	DeleteFile( TMPCOMMENTNAME );

	msg = msg_open( n->m->m.pufferID, n->m->m.mailID );
	if( !msg )
	{
		displaybeep();
		return( 0 );
	}

	rkey = LibCreatePool( MEMF_CLEAR, 1024, 256 );

	msg_copy( msg, TMPMSGNAME, MC_DATA );
	msg_copy( msg, TMPCOMMENTNAME, MC_COMMENT );

	/* Emps suchen */
	hlist = msg_loadheader( msg );

	hl = hl_findheader( hlist, "EMP" );
	while( hl )
	{
		empcount++;
		hl = hl_findnextheader(hl);
	}

	emplist=LibAllocPooled(rkey,empcount*4+4);
	empcount=0;
	hl=hl_findheader(hlist,"EMP");
	while(hl)
	{
		emplist[empcount]=LibAllocPooled(rkey,strlen(hl->data)+1);
		strcpy(emplist[empcount++],hl->data);
		hl=hl_findnextheader(hl);
	}
	emplist[empcount]=0;

	hl=hl_findheader(hlist,"ABS");
	buffer[0]=0;
	if(hl) strcpy(buffer,hl->data);

	hl=hl_findheader(hlist,"BET");
	bet[255]=bet[0]=0;
	if(hl) strncpy(bet,hl->data,255);

	hl=hl_findheader(hlist,"ZUSAMMENFASSUNG");
	comment[255]=comment[0]=0;
	if(hl) strncpy(comment,hl->data,255);

	msg_close( msg );

	hl = hl_findheader( hlist, "FILE" );

	rc=dosendwin("Nachricht weiterleiten...",bet,comment,0, 0,n->m->m.flags&MMF_BIN?1:0,
		buffer,emplist,0,0, NULL, NULL, hl ? hl->data : NULL, NULL
	);

	hl_freeheader( hlist );

	LibDeletePool(rkey);

	return(rc);
}

static int doweiterquiet( char **destlist, struct vmail *n )
{
	char buffer[256],bet[256],comment[256];
	long empcount=0;
	char **emplist;
	void *rkey;
	struct header *hl;
	int rc;
	struct msghandle *msg;
	struct hlist *hlist;

	DeleteFile( TMPMSGNAME );
	DeleteFile( TMPCOMMENTNAME );

	msg = msg_open( n->m->m.pufferID, n->m->m.mailID );
	if( !msg )
	{
		displaybeep();
		return( 0 );
	}

	rkey = LibCreatePool( MEMF_CLEAR, 1024, 256 );

	msg_copy( msg, TMPMSGNAME, MC_DATA );
	msg_copy( msg, TMPCOMMENTNAME, MC_COMMENT );

	/* Emps suchen */
	hlist = msg_loadheader( msg );

	hl = hl_findheader( hlist, "EMP" );
	while( hl )
	{
		empcount++;
		hl = hl_findnextheader(hl);
	}

	emplist=LibAllocPooled(rkey,empcount*4+4);
	empcount=0;
	hl=hl_findheader(hlist,"EMP");
	while(hl)
	{
		emplist[empcount]=LibAllocPooled(rkey,strlen(hl->data)+1);
		strcpy(emplist[empcount++],hl->data);
		hl=hl_findnextheader(hl);
	}
	emplist[empcount]=0;

	hl=hl_findheader(hlist,"ABS");
	buffer[0]=0;
	if(hl) strcpy(buffer,hl->data);

	hl=hl_findheader(hlist,"BET");
	bet[255]=bet[0]=0;
	if(hl) strncpy(bet,hl->data,255);

	hl=hl_findheader(hlist,"ZUSAMMENFASSUNG");
	comment[255]=comment[0]=0;
	if(hl) strncpy(comment,hl->data,255);

	msg_close( msg );

	hl = hl_findheader( hlist, "FILE" );

	rc = dosendwin( "Nachricht weiterleiten",
		bet,
		comment,
		NULL,
		destlist,
		n->m->m.flags & MMF_BIN ? 1 : 0,
		buffer,
		emplist,
		NULL,
		NULL,
		NULL,
		NULL,
		hl ? hl->data : NULL,
		NULL
	);

	//rc=dosendweiter( destlist, emplist, buffer, bet, comment, n->m->m.flags & MMF_BIN );

	hl_freeheader( hlist );

	LibDeletePool(rkey);

	return(rc);
}

static char *findqh( struct hlist *hlist, char *head )
{
	struct header *hl;
	static char buff2[128];
	char *p;

	if(!stricmp(head,"DAT") || !stricmp( head, "DATE" ) )
	{
		hl = hl_findheader( hlist, "EDA" );
		if( hl )
		{
			sprintf( buff2, "%2.2s.%2.2s.%4.4s",
				&hl->data[6],
				&hl->data[4],
				hl->data );
			return( buff2 );
				
				
		}
	}
	else if( !stricmp( head, "TIM" ) || !stricmp( head, "TIME" ) )
	{
		hl = hl_findheader(hlist,"EDA");
		if( hl )
		{
			int hoffset = atoi( &hl->data[ 15 ] );
			char hour[ 4 ];

			hour[ 0 ] = hl->data[ 8 ];
			hour[ 1 ] = hl->data[ 9 ];
			hour[ 2 ] = 0;

			sprintf( buff2, "%02ld:%2.2s:%2.2s",
				( atoi( hour ) + hoffset ) % 24,
				&hl->data[10],
				&hl->data[12] );
			return( buff2 );
		}
	}
	else if( !stricmp( head, "VORNAME" ) || !stricmp( head, "NAME1" ) )
	{
		hl = hl_findheader(hlist,"ABS");
		if( hl )
		{
			p = strchr( hl->data, '(' );
			if( p && !isspace( p[ 1 ] ) )
			{
				sbreakword( buff2, ++p, 0, 127);
				skillatch( buff2, ')' );
				return( buff2 );
			}
			else
			{
				strncpy( buff2, hl->data, 127 );
				skillatch( buff2, '%' );
				skillatch( buff2, '@' );
				return( buff2 );
			}
		}
	}
	else if(!stricmp(head,"NACHNAME") || !stricmp( head, "NAME2" ) )
	{
		hl=hl_findheader(hlist,"ABS");
		if(hl)
		{
			p=strchr(hl->data,'(');
			if(p++)
			{
				sbreakword(buff2,p,-1,127);
				skillatch( buff2, ')' );
				return( buff2 );
			}
		}
	}
	hl = hl_findheader( hlist, head );
	if(hl)
	{
		return( hl->data );
	}

	return( "" );
}


static void doquoteheader(struct hlist *hlist, FILE *to,long public)
{
	FILE *head;
	char buff[64];
	int ch,c;

	strcpy( buff, ( public ) ? "md_qh.pub" : "md_qh.priv" );
	if( cmb->b.language )
		asprintf( buff, ".%ld", cmb->b.language );

	head = fopen( buff, "r" );
	if(!head)
		return; 

	while((ch=fgetc(head))!=EOF)
	{
		if(ch=='$')
		{
			for(c=0; c<64; c++)
			{
				ch=fgetc(head);
				if(ch==EOF||ch=='$') break;
				buff[c]=ch;
			}
			buff[c]=0;

			if( !c )
			{
				fputc( '$', to );
				continue;
			}

			fprintf( to, findqh( hlist, buff ) );
		}
		else
			fputc( ch, to );
	}
	fclose( head );
}

static int donewmail( char *binfile, struct mbrett *cmb, char *emp )
{
	int rc;
	char *emplist[2];
	struct brettinfo *bi=getbrettinfo(cmb);
	FILE *f;
	int origin = 1;

	emplist[ 0 ] = emp;
	emplist[ 1 ] = NULL;

	if( ( cmb->b.name[0] == '/' ) && ( cmb->b.name[ 1 ] != '»' ) )
	{
		emplist[0] = cmb->b.name;
	}
	else
	{
		origin = 0;
		if( bi->antwortan[ 0 ] )
			emplist[ 0 ] = bi->antwortan;
	}

	f = fopen( TMPMSGNAME, "w" );
	if( !f )
	{
		displaybeep();
		return(0);
	}
	doorigin( f, origin, cmb );
	fclose(f);

	rc=dosendwin( "Neue Nachricht...",
		NULL,NULL,
		NULL,
		emplist,
		binfile ? 2 : 0,
		0,0,bi->diskussionin[0]?bi->diskussionin:0,0,
		NULL,
		binfile,
		NULL,
		NULL
	);
	return(rc);
}

static int doanswermail(struct vmail *n,int public,int quote)
{
	char *emp[128],*p;
	char qc[4];
	int rc,c;
	int flags = 0;
	char buffer[1024];
	char betreff[256];
	char fto[ 128 ];
	struct header *hl, *hl2;
	struct brettinfo *bi=getbrettinfo(cmb);
	struct msghandle *msg;
	struct hlist *hlist;
	FILE *f;

	if( !n )
	{
		displaybeep();
		return( 0 );
	}

	/* Falls PM, keine öffentliche Antwort möglich */
	if( public && cmb->b.name[0] != '/' && !( cmb->b.flags & BFLAG_EXTEND_PM ) )
	{
		return( donewmail( NULL, cmb, !strnicmp( n->m->m.absender, "an ", 3 ) ? &n->m->m.absender[ 3 ] : n->m->m.absender ) );
	}

	qc[0]=0;

	// Filter flag errors...

	if( quote )
		quote = 1;

	if( ( n->m->m.flags & MMF_BIN ) && quote )
		quote = 2;

	msg = msg_open( n->m->m.pufferID, n->m->m.mailID );
	if( !msg )
	{
		displaybeep();
		return( 0 );
	}

	hlist = msg_loadheader( msg );

	f = fopen( TMPMSGNAME, "w" );

	/* Header alle vorhanden */
	hl = hl_findheader(hlist,"BET");
	betreff[255]=0;
	sprintf( betreff, "Re: %.247s", skipre( hl->data ) );
	fto[ 0 ] = 0;

	hl=hl_findheader(hlist,"ABS");
	if(!hl)
	{
		/* Von uns */
		hl = hl_findheader( hlist, "EMP" );
		if( hl && hl->data && ( ( cmb->b.name[ 0 ] != '/' ) || ( !strcmp( cmb->b.name, "/»SPOOL" ) ) ) )
			strcpy( buffer, hl->data );
		else
			sprintf( buffer, "%s@%s%s (%s)", prefs.username, ISRFC ? prefs.pointname : prefs.boxname, prefs.boxdomain, prefs.userrealname );
		hl_addheader( hlist, "ABS", buffer );
	}
	else
	{
		p = strchr( hl->data, '(' );
		if( p )
		{
			stccpy( fto, stpblk( p + 1 ), sizeof( fto ) );
			p = strrchr( fto, ')' );
			if( p )
				*p = 0;
		}
	}

	if(!public)
	{
		int gotaa = FALSE;

		c = 0;
		hl = hl_findheader( hlist, "ANTWORT-AN" );
		if( hl )
		{
			// check for mailinglist
			if( cmb->b.flags & BFLAG_EXTEND_PM )
			{
				struct brettinfo *bi = getbrettinfo( cmb );

				if( !stricmp( hl->data, bi->antwortan ) )
					hl = NULL;
			}


			while( hl )
			{
				emp[ c++ ] = hl->data;
				hl = hl_findnextheader( hl );
				gotaa = TRUE;
			}
		}

		if( !gotaa )
		{
			hl = hl_findheader( hlist, "ABS" );
			if( hl )
				emp[ c++ ] = hl->data;
		}

		hl = hl_findheader( hlist, "OAB" );
		if( hl )
			emp[ c++ ] = hl->data;

		/*hl = hl_findheader( hlist, "WAB" );
		if( hl )
			emp[ c++ ] = hl->data;*/

		emp[ c ] = 0;
	}
	else
	{
		hl=hl_findheader( hlist, "DISKUSSION-IN" );
		if(!hl)
		{
			if( bi->diskussionin[0] )
			{
				emp[0]=bi->diskussionin;
				emp[1]=0;
			}
			else if( bi->antwortan[0] )
			{
				emp[0]=bi->antwortan;
				emp[1]=0;
			}
			else			
			{
				hl = hl_findheader( hlist, "EMP" );
				for(c=0; hl && c<127; c++)
				{
					emp[c]=hl->data;
					hl=hl_findnextheader(hl);
				}
				emp[c] = NULL;
			}
		}
		else
		{
			/* Diskussion in vorhanden */
			for( c=0; hl && c<127; c++ )
			{
				emp[c]=hl->data;
				hl=hl_findnextheader(hl);
			}
			emp[c] = NULL;
		}
	}

	/* Quoten */
	if( quote && ( quote != 2 || msg_getsize( msg, MC_COMMENT ) ) )
	{
		hl=hl_findheader(hlist,"ABS");
/*		p=strchr(hl->data,'(');
		if(p && p[1] != ')' && p[2] != ')' )
		{
			if( p[1] == '\"' )
				p++;
			qc[0]=p[1];
			if( p[2] )
				qc[1]=p[2];
			else
				qc[1]=qc[0];
			p = strrchr(p,' ');
			if(p) qc[1]=p[1];
		}
		else
		{
			strcpy( buffer, hl->data );
			p = strchr( buffer, '%' );
			if( p )
				*p = 0;
			p = strchr( buffer, '@' );
			if( p )
				*p = 0;
			qc[0]=buffer[0];
			p=strchr(buffer,'_');
			if(!p) p=strchr(buffer,'.');
			if(!p) p=strchr(buffer,'-');
			if(p)
				qc[1]=p[1];
		 	else
				qc[1] = buffer[strlen(buffer) - 1 ];
		}
		qc[2] = '>';
		qc[3] = 0; 
		qc[ 0 ] = '>';
		qc[ 1 ] = 0;*/
		doquoteheader(hlist,f,public);
		c=0;

		// Kommentar auch quoten

		if( msg_getsize( msg, MC_COMMENT ) > 0 )
		{
			msg_initread( msg, MC_COMMENT );

			while( msg_read( msg, buffer, sizeof( buffer ) ) )
			{
				clnl(buffer);
				if(!buffer[0] && !c) continue;
				else c=1;
				fprintf(f,"> %s\n",buffer);
			}

			if( quote != 2 )
				fprintf( f, "\n" );

			msg_endread( msg );
		}

		c = 0;
		if( quote != 2 )
		{
			msg_initread( msg, MC_DATA );

			while( msg_read( msg, buffer, sizeof( buffer ) ) )
			{
				clnl(buffer);
				if(!buffer[0] && !c) continue;
				else c=1;
				fprintf(f,"> %s\n", buffer );
			}
			msg_endread( msg );
		}
	}

	doorigin(f,public,cmb);

	fclose(f);

	msg_close( msg );

	hl2 = hl_findheader( hlist, "BEZ" );
	if( hl2 == hl_findlastheader( hlist, "BEZ" ) )
		hl2 = NULL;
	/*if( !hl2 )
		hl2 = hl_findheader( hlist, "BEZ" );*/

	hl = hl_findheader( hlist, "MID" );
	rc = dosendwin((public)?"Öffentliche Antwort...":"Private Antwort...",
		betreff,0,
		hl->data, emp,
		flags,
		0,0,
		bi->diskussionin[0] ? bi->diskussionin : NULL,
		qc[0]?qc:NULL,
		hl2 ? hl2->data : NULL,
		NULL,
		NULL,
		fto[ 0 ] ? fto : NULL
	);

	hl_freeheader( hlist );
	return(rc);

}

static int doanswer(int public,int quote)
{
	struct vmail *n=(struct vmail*)mlist.lh_Head;
	int rc=0;
	struct mbrett *personal=findbrett(0,0);

	/* Im privaten Brett */
	if(personal==cmb) public=0;

	if(!mmcount)
	{
		n=(struct vmail*)GetEntry(&mlist,getscrollercurrent());
		rc=doanswermail(n,public,quote);
		return(rc);
	}
	savesel();
	while(n->n.mln_Succ)
	{
		if(n->sel)
		{
			rc|=doanswermail(n,public,quote);
			n->sel=0;
		}
		n=(struct vmail*)n->n.mln_Succ;
	}
	return(rc);
}

void excludemail(struct msghandle *msg,char *to,BOOL withheader,int bin)
{
	BPTR f2;
	int rc;

	/* Prüfen, ob Datei da */
	rc = fileexistsreq( to );

	if( !rc )
		return;
	else if( rc == 1 )
		f2 = Open( to, MODE_NEWFILE );
	else if( rc == 2 )
	{
		f2 = Open( to, MODE_OLDFILE );
		if( !f2 )
		{
			return;
		}
		Seek( f2, 0, OFFSET_END );
	}

	if(!f2) {
		rc = IoErr();
		nofilereq( to, rc );
		return;
	}

	msg_copyfh( msg, f2, MC_DATA | ( withheader ? ( MC_HEADER | MC_COMMENT ) : 0 ) );

	Close(f2);

	/* Icon erzeugen */
	if(bin!=42)
	{
		createdataicon(to,(bin)?prefs.binex_defaulttool:prefs.txtex_defaulttool);
	}
}

void excludemailquiet(struct msghandle *msg,char *to,BOOL withheader,BOOL bin,BOOL append)
{
	BPTR f2;
	int rc;

	if( append )
	{
		f2 = Open( to, MODE_OLDFILE );
		if( f2 )
			Seek( f2, 0, OFFSET_END );
		else
			f2 = Open( to, MODE_NEWFILE );
	}
	else
		f2 = Open( to, MODE_NEWFILE );

	if(!f2)
	{
		rc = IoErr();
		nofilereq( to, rc );
		return;
	}

	msg_copyfh( msg, f2, MC_DATA | ( withheader ? ( MC_HEADER | MC_COMMENT ) : 0 ) );

	Close(f2);

	/* Icon erzeugen */
	if(bin!=42)
	{
		createdataicon(to,(bin)?prefs.binex_defaulttool:prefs.txtex_defaulttool);
	}
}

static void domailinfo( struct vmail * n )
{
	struct msghandle *msg = msg_openv( n );

	if( !msg )
		return;

	askreq( "\Position: %ld:%ld\nFlags...: %ld\nOffset..: %ld\nHeader..: %ld\nComment.: %ld\nData....: %ld",
		"Absturz",
		n->m->m.pufferID, n->m->m.mailID,
		msg->pix.flags,
		msg->pix.offset,
		msg->pix.headersize,
		msg->pix.commentsize,
		msg->pix.datasize
	);

	msg_close( msg );

}

static void doviewmail(struct vmail *n)
{
	char ex[ 256 ];
	struct msghandle *msg;
	struct mmail *m = n->m;

	if( ( ( ! ( m->m.flags & MMF_READ ) || ( m->m.flags&MMF_SHOW ) ) ) )
	{
		m->m.flags|=MMF_READ;
		m->m.flags&=~MMF_SHOW;
		mix->changed=1;
	}

	if( ( prefs.flags2 & MDF2_AUTOCLRNEW ) && ( m->m.flags & MMF_UNSEEN ) )
	{
		m->m.flags &= ~MMF_UNSEEN;
		mix->changed = 1;
	}

	msg = msg_openv( n );
	if( !msg )
		return;
	msg_copy( msg, "T:mdview.temp", MC_DATA );
	msg_close( msg );

	sprintf( ex, prefs.binviewer, "T:mdview.temp", 0, 0, 0, 0, 0, 0 );

	if( !wbwindow && prefs.viewer_wb )
		WBenchToFront();

	if( isv37 )
	{
		SystemTags( ex, NP_StackSize, max( prefs.viewer_stack, 4096 ), TAG_DONE );
	}
	else
	{
		system( ex );
	}
	DeleteFile("T:mdview.temp");
	ScreenToFront( scr );
}


static void makebetfilename(char *name)
{
	char *to=name;

	while(*name) {
		if( ! ( ( isalpha(*name) ) || ( isdigit(*name) ) || ( *name == '.' ) || ( *name == '_' ) || ( *name == '-' ) ) )
		{
			*to++='_';
			while(*name && !isalpha(*name)) name++;
		}
		else *to++=*name++;
	}
	if( to[-1] == '_' ) to[-1]=0;
	else *to=0;
}

static int huntit( char *from, char ch )
{
	if( *from == ch )
		return( 0 );

	while( *from && strchr( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789öäüÖÄÜßøØ®©", *from ) )
		from++;
	return( ( *from == ch ) && strchr( "`'´`():;!.,  \t", from[ 1 ] ) );
}

#define STYLE_ITALIC
static void stylenode( char *txt, int len, char *cpy, char *sty )
{
	int c, d;
	int cs = FS_NORMAL;

	for( c = 0, d = 0; c < len; c++ )
	{
		sty[ d ] = cs;
		if( txt[ c ] == '*' )
		{
			if( cs & FSF_BOLD )
			{
				cs &= ~FSF_BOLD;
			}
			else
			{
				if( ( !c || isspace( txt[ c - 1 ] ) ) && huntit( &txt[ c + 1 ], '*' ) )
					cs |= FSF_BOLD;
				else
				{
					cpy[ d++ ] = txt[ c ];
				}
			}
		}
		else if( txt[ c ] == '_' )
		{
			if( cs & FSF_UNDERLINED )
			{
				cs &= ~FSF_UNDERLINED;
			}
			else
			{
				if( ( !c || isspace( txt[ c - 1 ] ) ) && huntit( &txt[ c + 1 ], '_' ) )
					cs |= FSF_UNDERLINED;
				else
					cpy[ d++ ] = txt[ c ];
			}
		}
#ifdef STYLE_ITALIC
		else if( txt[ c ] == '/' )
		{
			if( cs & FSF_ITALIC )
			{
				cs &= ~FSF_ITALIC;
			}
			else
			{
				if( ( !c || isspace( txt[ c - 1 ] ) ) && huntit( &txt[ c + 1 ], '/' ) )
					cs |= FSF_ITALIC;
				else
					cpy[ d++ ] = txt[ c ];
			}
		}
#endif
		else
			cpy[ d++ ] = txt[ c ];
		
	}
	cpy[ d ] = 0;
}

#define PW_CANCEL 1
#define PW_GCM 2
#define PW_INFO 3
#define PW_GALL 4

static APTR printogw;
static int printcount, printmax, printabort;
static void initprintwin( void )
{
	static char windowtitle[ 80 ];
	APTR ogw;
	struct Window *iw;

	printmax = mmcount ? mmcount : 1;
	printcount = 0;
	printabort = FALSE;

	lockwindow();
	if( mmcount )
		sprintf( windowtitle, "%lD Nachrichten drucken...", mmcount );
	else
		strcpy( windowtitle, "Nachricht drucken" );
	ogw = ogreInitWindow( scr, 0, 0, windowtitle );
	ogreAddGroup( ogw, 0 | OGGP_EXPANDSTRING, OGFRAME_NONE, NULL );
	ogreAddText( ogw, 0, "Info:", PW_INFO, "", 40, 1 );
	ogreAddFuelGauge( ogw, 1, PW_GCM, 0 );
	if( mmcount )
		ogreAddFuelGauge( ogw, 2, PW_GALL, mmcount );
	ogreAddButton( ogw, ( mmcount ? 3 : 2 ) | OGB_ONESC, 'a', "_Abbruch", PW_CANCEL );

	iw = ogreOpenWindow( ogw );
	if( !iw )
	{
		unlockwindow();
		return;
	}
	printogw = ogw;
}

static void closeprintwin( void )
{
	if( !printogw )
		return;

	ogreExitWindow( printogw );
	printogw = NULL;
	unlockwindow();
}

static int safeprint( BPTR pr, char *buffer, int len )
{
	int rc;

	if( len < 0 )
		len = strlen( buffer );

	for(;;)
	{
		struct IntuiMessage *im;

		while( im = ogreIM( printogw ) )
		{
			if( ( im->Class == IDCMP_GADGETUP )	&& ( im->Code == PW_CANCEL ) )
				printabort = TRUE;
			ogreIMReply( printogw, im );
		}

		if( printabort )
		{
			if( askreq( "Druckvorgang abbrechen?", "Drucken abbrechen|Weiter" ) )
				return( -1 );
			printabort = FALSE;
		}

		rc = Write( pr, buffer, len );
		if( rc == len )
			return( 0 );

		rc = askreq( "Fehler %ld beim Drucken!", "Wiederholen|Abbruch", IoErr() );
		if( !rc )
			return( -1 );
	}
}

static int printmsg( struct msghandle *msg, LONG what, BPTR prt )
{
	UBYTE buf[ 1024 ];
	UBYTE new[ 1024 ];
	UBYTE sty[ 1024 ];
	int c, cs, e, slen;
	char stycmd[ 32 ];
	int len;
	int rc = 0;
	int ppos = 0;

	msg_initread( msg, what );

	while( msg_read( msg, buf, 1024 ) )
	{
		ppos += strlen ( buf );
		ogreSetValue( printogw, PW_GCM, ppos );

		if( prefs.flags & MDF_NOREADERSTYLES )
		{
			rc = safeprint( prt, buf, -1 );
			if( rc )
				goto xit;
		}		
		else
		{
			stylenode( buf, 1024, new, sty );
			len = strlen( new );
			// Nun printen
			for( c = 0; c < len; )
			{
				cs = sty[ c ];
				for( e = c + 1; ( e < len ) && ( sty[ e ] == cs ); e++ );
				slen = e - c;

				strcpy( stycmd, "\x1b[0m" );
				if( cs )
				{
					strcat( stycmd, "\x1b[" );
					if( cs & FSF_BOLD )
						strcat( stycmd, "1;" );
					if( cs & FSF_UNDERLINED )
						strcat( stycmd, "4;" );
					if( cs & FSF_ITALIC )
						strcat( stycmd, "3;" );
					strcpy( strchr( stycmd, 0 ) - 1, "m" );
				}
				rc = safeprint( prt, stycmd, -1 );
				if( rc )
					goto xit;
				rc = safeprint( prt, &new[ c ], slen );
				if( rc )
					goto xit;
				c += slen;
			}
		}
		rc = safeprint( prt, "\n", 1 );
		if( rc )
			goto xit;
	}
	rc = safeprint( prt, "\x1b[0m\n", -1 );
xit:
	msg_endread( msg );
	return( rc );
}

static int doprintmail(struct vmail *n)
{
	struct header *hl;
	char *p2;
	int rc;
	BPTR prt;
	int bin;
	struct msghandle *msg;
	struct hlist *hlist;
	int cpw = FALSE;
	int msgsize;

	if( printabort )
		return( -1 );

	if( !printogw )
	{
		initprintwin();
		cpw = TRUE;
	}

	if( printogw )
	{
		char bf[ 128 ];
		sprintf( bf, "Drucke Nachricht %ld von %ld", ++printcount, printmax );
		ogreSetStringValue( printogw, PW_INFO, bf );
		if( mmcount )
			ogreSetValue( printogw, PW_GALL, printcount );
		ogreSetValue( printogw, PW_GCM, 0 );
	}

	msg = msg_openv( n );
	if( !msg )
	{
		if( cpw )
			closeprintwin();
		printabort = TRUE;
		return( -1 );
	}

	msgsize = msg_getsize( msg, MC_COMMENT ) + msg_getsize( msg, MC_DATA );
	ogreSetMaxVal( printogw, PW_GCM, msgsize );

	bin = n->m->m.flags & MMF_BIN;

	hlist = msg_loadheader( msg );

/*	hl = hl_findheader( hlist, "TYP" );
	if( hl && hl->data && !stricmp( hl->data, "BIN" ) )
		bin = TRUE;*/

retry:
	prt = Open( "PRT:", MODE_NEWFILE );
	if( !prt )
	{
		if( askreq("Drucker ist nicht ansprechbar (%ld)!","Wiederholen|Abbruch", IoErr() ) )
			goto retry;
		hl_freeheader( hlist );
		msg_close( msg );
		if( cpw )
			closeprintwin();
		printabort = TRUE;
		return( -1 );
	}

	/* Erst Header drucken... */
	hl = hl_findheader( hlist, NULL );
	while( hl->n.mln_Succ )
	{
		p2 = translateheader( hl->head, hl->data );
	
		if( rc = safeprint( prt, "\x1b[1m", -1 ) )
			goto abortprint;
		if( rc = safeprint( prt, p2, -1 ) )
			goto abortprint;
		rc = 20 - strlen( p2 );

		if( rc > 0 )
		{
			if( rc = safeprint( prt, "....................", rc ) )
				goto abortprint;
		}
		if( rc = safeprint( prt, ":\x1b[0m ", -1 ) )
			goto abortprint;
		if( rc = safeprint( prt, (datmem[0]) ? datmem : hl->data, -1 ) )
			goto abortprint;
		if( rc = safeprint( prt, "\n", 1 ) )
			goto abortprint;
		hl = ( struct header * ) hl->n.mln_Succ;
	}

	if( rc = safeprint( prt, "\n", 1 ) )
		goto abortprint;

	/* Copy rest der nachricht */
	if( bin )
	{
		if( rc = printmsg( msg, MC_COMMENT, prt ) )
			goto abortprint;
		rc = safeprint( prt, "\nBinärdatei.\n", -1 );
	}
	else
	{
		if( rc = printmsg( msg, MC_COMMENT, prt ) )
			goto abortprint;
		rc = printmsg( msg, MC_DATA, prt );
	}

abortprint:
	Close( prt );
	msg_close( msg );
	hl_freeheader( hlist );
	if( cpw )
		closeprintwin();

	if( rc )
		printabort = TRUE;
	return( rc );
}

static void doprintmsg( void )
{
	initprintwin();
	iteratemsglist( doprintmail );
	closeprintwin();
}

struct vmail *getcurrentmail( void )
{
	if( rexxmode == 2)
		return( currentreadermail );
	else
		return( ( struct vmail * ) GetEntry( &mlist, getscrollercurrent() ) );
}

struct msghandle *opencurrentmail( void )
{
	struct vmail *vm = getcurrentmail();
	struct msghandle *msg = NULL;

	if( vm )
	{
		msg = msg_open( vm->m->m.pufferID, vm->m->m.mailID );
	}
	return( msg );
}

struct mbrett *getcurrentbrett( void )
{
	return( cmb );
}

#define DEC(c)  (((c) - ' ') & 077)

static void outdec( char *p, FILE *f, int n)
{
	int c1, c2, c3;

	c1 = DEC(*p) << 2 | DEC(p[1]) >> 4;
	c2 = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
	c3 = DEC(p[2]) << 6 | DEC(p[3]);
	if (n >= 1)
		putc(c1, f);
	if (n >= 2)
		putc(c2, f);
	if (n >= 3)
		putc(c3, f);
}

void excludemailuudecode( struct msghandle *msg, char *to )
{
	FILE *f;
	int rc;
	char line[ 256 ];
	char *p;
	int endfound = FALSE;

	/* Prüfen, ob Datei da */
	rc = fileexistsreq( to );

	if( !rc )
		return;
	else if( rc == 1 )
		f = fopen( to, "w" );
	else if( rc == 2 )
		f = fopen( to, "a" );

	if(!f)
	{
		rc = IoErr();
		nofilereq( to, rc );
		return;
	}

	while( msg_read( msg, line, 256 ) )
	{
		if( !strnicmp( line, "end", 3 ) )
		{
			endfound = TRUE;
			break;
		}

		rc = DEC( line[ 0 ] ) ;
		if( rc < 0 || rc > 63 )
		{
			break;
		}

		p = &line[ 1 ];
		while( rc > 0 )
		{
			outdec( p, f, rc );
			rc -= 3;
			p += 4;
		}
	}

	if( !endfound )
	{
		askreq( "Warnung! Keine \"end\"-Zeile gefunden.\nDie Datei kann unvollständig sein.", "Weiter" );
	}

	msg_endread( msg );

	fclose( f );

	/* Icon erzeugen */
	createdataicon( to, prefs.binex_defaulttool );
}


static void doextractmailuudecode( struct vmail *n )
{
	char file[108],path[256];
	struct msghandle *msg;
	struct brettinfo *bi=getbrettinfo(cmb);
	char *p;

	file[0]=file[107]=0;

	msg = msg_openv( n );
	if( !msg )
		return;

	msg_initread( msg, MC_DATA );

	while( msg_read( msg, path, 256 ) )
	{
		if( !strncmp( path, "begin ", 6 ) )
			goto found;
	}

	msg_endread( msg );
	msg_close( msg );
	askreq( "Keine \"begin\"-Zeile gefunden.\nDies ist keine UUEncodete Nachricht.", "Abbruch" );

	return;

found:

	p = stpblk( &path[ 6 ] );
	if( p )
	{
		p = strchr( p, ' ' );
		if( p )
			strcpy( file, stpblk( p ) );
	}

	if( bi && bi->autoexpfad[0] )
		rtChangeReqAttr( fr[ FR_EXCLUDE_BIN ], RTFI_Dir, bi->autoexpfad, TAG_DONE );

	if( rtFileRequest(fr[ FR_EXCLUDE_BIN ],file,"Nachricht UUDecoden...",
		RT_Window,w,
		RT_ReqPos,REQPOS_CENTERSCR,
		RT_LockWindow,TRUE,
		RTFI_Flags,FREQF_SAVE,
		TAG_DONE))
	{
			strcpy(path,fr[ FR_EXCLUDE_BIN ]->Dir);
			addpart(path,file);
			excludemailuudecode( msg, path );
	}
	msg_close( msg );
}


static void doextractmail(struct vmail *n,BOOL withheader)
{
	char file[108],path[256];
	struct header *hl;
	struct hlist *hlist;
	struct msghandle *msg;
	struct brettinfo *bi=getbrettinfo(cmb);
	int frnum;

	file[0]=file[107]=0;

	msg = msg_openv( n );
	if( !msg )
		return;

	frnum = (n->m->m.flags & MMF_BIN) ? FR_EXCLUDE_BIN : FR_EXCLUDE;

	hlist = msg_loadheader( msg );
	hl = hl_findheader(hlist,"FILE");
	if(!hl) {
		hl=hl_findheader(hlist,"BET");
		if(hl) {
			strncpy(file,hl->data,107);
			makebetfilename(file);
		}
	}
	else strncpy(file,hl->data,107);

	if( bi && bi->autoexpfad[0] )
		rtChangeReqAttr( fr[ frnum ], RTFI_Dir, bi->autoexpfad, TAG_DONE );

	if( rtFileRequest(fr[frnum],file,"Nachricht exportieren...",
		RT_Window,w,
		RT_ReqPos,REQPOS_CENTERSCR,
		RT_LockWindow,TRUE,
		RTFI_Flags,FREQF_SAVE,
		TAG_DONE))
	{
			strcpy(path,fr[frnum]->Dir);
			addpart(path,file);
			excludemail(msg,path,withheader,n->m->m.flags&MMF_BIN);
	}
	hl_freeheader(hlist);
	msg_close( msg );
}

static void doextractmailquiet( struct vmail *n, char *dir, BOOL withheader )
{
	char file[108],path[256];
	struct header *hl;
	struct hlist *hlist;
	struct msghandle *msg;

	msg = msg_openv( n );

	if( !msg )
		return;

	hlist = msg_loadheader( msg );

	hl = hl_findheader(hlist,"FILE");
	if(!hl)
	{
		hl=hl_findheader(hlist,"BET");
		if(hl)
		{
			strncpy(file,hl->data,107);
			makebetfilename(file);
		}
	}
	else strncpy(file,hl->data,107);

	strcpy(path,dir);
	addpart(path,file);
	excludemailquiet( msg, path, withheader, n->m->m.flags & MMF_BIN, FALSE );
	hl_freeheader(hlist);

	msg_close( msg );
}


#define DX_OK 1
#define DX_CANCEL 2
#define DX_MODE 3
#define DX_HEADER 4
#define DX_DIR 5
#define DX_DIRSEL 6

static char *dx_options[] = { "einzelne Dateien", "Einzeln ohne Nachfrage", "Gesammelt in eine Datei", NULL };

static void doextractmsg( BOOL withheader )
{
	struct vmail *n=(struct vmail*)mlist.lh_Head;
	char windowtitle[ 42 ];
	int Done = FALSE;
	struct ogwin *ogw;
	struct IntuiMessage *im;
	struct Window *iw;
	static UWORD xmode, xheader;
	static char xpath[ 256 ];
	int rc;

	if( !mmcount )
	{
		n=(struct vmail*)GetEntry(&mlist,getscrollercurrent());
		doextractmail( n, withheader );
		return;
	}

	if( !xpath[ 0 ] )
		strcpy( xpath, prefs.binex_pfad );

	/* Mehrere Markiert */
	lockwindow();
	sprintf( windowtitle, "%lD Nachrichten auslagern...", mmcount );
	ogw = ogreInitWindow( scr, 0, 0, windowtitle );
	ogreAddGroup( ogw, 0 | OGGP_EXPANDSTRING, OGFRAME_OUTLINE, " Parameter " );
	ogreAddCycle( ogw, 0, 'd', "_Dateien", DX_MODE, dx_options, 28, xmode );
	ogreAddCheckbox( ogw, 1, 'h', "mit _Header auslagern", DX_HEADER, xheader );
	ogreAddString( ogw, 2, 'p', "_Pfad:", DX_DIR, xpath, 30, 128 );
	ogreAddButton( ogw, 2 | OGGP_KEEPSIZE, 'P', "?", DX_DIRSEL );

	ogreAddGroup( ogw, 1, OGFRAME_NONE, NULL );
	ogreAddButton( ogw, 0 | OGB_ONENTER, 'o', "_OK", DX_OK );
	ogreAddHelp( ogw, 0 );
	ogreAddButton( ogw, 0 | OGB_ONESC, 'a', "_Abbruch", DX_CANCEL );

	iw = ogreOpenWindow( ogw );
	if( !iw )
	{
		unlockwindow();
		return;
	}

	while( !Done )
	{
		ogreEnable( ogw, xmode, DX_DIR, DX_DIRSEL, 0 );

		im = ogreWaitIM( ogw );
		if( im->Class == IDCMP_GADGETHELP)
			showguidenum( "excludewin_gads", im->Code );
		else if( im->Class == IDCMP_GADGETUP )
		{
			switch( im->Code )
			{
				case DX_MODE:
					xmode = ogreValue( ogw, DX_MODE );
					break;

				case DX_OK:
					if( xmode == 2 )
					{
						BPTR lock;

						ogreCopyStringValue( ogw, DX_DIR, xpath );
						if( lock = Lock( xpath, SHARED_LOCK ) )
						{
							struct FileInfoBlock *fib = allocfib();
							int isdir;
							Examine( lock, fib );
							isdir = fib->fib_DirEntryType > 0;
							UnLock( lock );
							freefib( fib );
							if( isdir )
							{
								askreq( "Beim gesammelten Auslagern in eine Datei\nmüssen Sie einen Dateinamen angeben!", "Abbruch" );
								break;
							}
						}
					}

					Done = 2;
					break;

				case DX_CANCEL:
					Done = 1;
					break;

				case DX_DIRSEL:
					if( xmode == 1 )
						newdofrseldir( ogw, DX_DIR, "Auslagerpfad:" );
					else
						newdofrselfile( ogw, DX_DIR, "Auslagerdatei:" );
					break;
			}
		}
		ogreIMReply( ogw, im );
	}

	xmode = ogreValue( ogw, DX_MODE );
	xheader = ogreValue( ogw, DX_HEADER );
	ogreCopyStringValue( ogw, DX_DIR, xpath );

	if( Done == 2 )
	{
		savesel();
		switch( xmode )
		{
			case 0:
				while( n->n.mln_Succ )
				{
					if( n->sel )
					{
						doextractmail( n, xheader );
						n->sel = 0;
					}
					n = ( struct vmail * ) n->n.mln_Succ;
				}
				break;

			case 1:
				while( n->n.mln_Succ )
				{
					if( n->sel )
					{
						doextractmailquiet( n, xpath, xheader );
						n->sel = 0;
					}
					n = ( struct vmail * ) n->n.mln_Succ;
				}
				break;

			case 2:
				rc = fileexistsreq( xpath );
				if( rc == 1 )
					DeleteFile( xpath );
				else if( !rc )
					break;

				while( n->n.mln_Succ )
				{
					if( n->sel )
					{
						struct msghandle *msg = msg_openv( n );
						excludemailquiet( msg, xpath, xheader, n->m->m.flags & MMF_BIN, TRUE );
						msg_close( msg );
						n->sel = 0;
					}
					n = ( struct vmail * ) n->n.mln_Succ;
				}
				break;
		}
	}

	ogreExitWindow( ogw );
	unlockwindow();

	return;
}

static void doviewmsg(void)
{
	iteratemsglist( doviewmail );
}

void freeinhalt(void)
{
	if(mix)
	{
		preport( 1, 1, "Speichere Brettindex..." );
		freemlist();
		savebrettix(mix,cmb);
		freebrettix(mix);
		mix=0;
	}
}



static void dofold(int mode)
{
	struct vmail *n=(struct vmail*)mlist.lh_Head;

	/*rtSetWaitPointer(w);*/

	mix->changed=1;

	if( mode == 3 )
	{
		n = (struct vmail *) GetEntry( &mlist, getscrollercurrent() );
		if( !n )
			return;
		n = findparentmail( n );
		if( !n )
			return;
		n->m->m.flags ^= MMF_FOLD;
		lastmailnum = GetEntryNum( &mlist, (struct Node *) n );

		return;
	}

	if(mode)
	{
		while(n->n.mln_Succ)
		{
			if(mode==1 && !n->m->parent && n->m->firstbez )
				n->m->m.flags |= MMF_FOLD;
			else
				n->m->m.flags &= ~MMF_FOLD;
			n=(struct vmail*)n->n.mln_Succ;
		}
		return;
	}

	if(!mmcount)
	{
		n=(struct vmail*)GetEntry(&mlist,getscrollercurrent());
		if( n )
			n->m->m.flags^=MMF_FOLD;
		return;
	}
	savesel();
	while(n->n.mln_Succ)
	{
		if(n->sel)
		{
			n->m->m.flags^=MMF_FOLD;
			n->sel=0;
		}
		n=(struct vmail*)n->n.mln_Succ;
	}
}

static void removekilled( struct mindex *mix )
{
	struct mmail *m = ( struct mmail * )mix->maillist.lh_Head, *next;

	while( next = ( struct mmail * ) m->n.mln_Succ )
	{
		if( m->m.flags & MMF_KILL )
			Remove( m );
		m = next;
	}
}

static void dokillthread(struct mmail *n,int deep, FILE *f)
{
	struct msghandle *msg;
	struct hlist *hlist;
	struct header *hl;

	rtSetWaitPointer(w);
	n->m.flags |= MMF_KILL;
	mix->changed = 1;

	msg = msg_open( n->m.pufferID, n->m.mailID );
	if( !msg )
		return;

	hlist = msg_loadheader( msg );
	hl = hl_findheader( hlist, "MID" );
	if( hl )
	{
		if( !f )
			addmke( hl->data );
		else
		{
			long t;
			time( &t );
			fwrite( &t, 4, 1, f );
			fprintf( f, "%s\n", hl->data );
		}
	}

	hl_freeheader( hlist );
	msg_close( msg );

	Remove( n );

	if(n->firstbez)
		dokillthread(n->firstbez,1,f);
	if(deep && n->bezlink)
		dokillthread(n->bezlink,1,f);
}

static int killthread(void)
{
	struct vmail *n=(struct vmail*)mlist.lh_Head;
	FILE *f;

	if( !mmcount && !GetNumEntries( &mlist ) )
	{
		displaybeep();
		return( 0 );
	}

	if( !askreq(
		"WARNUNG! %lD Thread%s wirklich killen?\nDie Nachrichten und alle Antworten darauf werden\ngelöscht und können nicht mehr restauriert werden!",
		"Killen|Abbruch",
			mmcount ? mmcount : 1,
			mmcount > 1 ? "s" : "") )
		return(0);

	pushhomedir();
	f = fopen("microdot.kill","a");
	if(!f) f=fopen("microdot.kill","w");
	popdir();

	rtSetWaitPointer(w);
	mix->changed=1;
	if( !mmcount )
	{
		n=(struct vmail*)GetEntry(&mlist,getscrollercurrent());
		dokillthread( n->m, 0, f );
		if( f )
			fclose( f );
		n->m->m.flags|=MMF_KILL;
		removekilled( mix );
		return(-1);
	}
	savesel();
	while( n->n.mln_Succ )
	{
		if( n->sel )
		{
			dokillthread(n->m,0,f);
			n->sel=0;
		}
		n=(struct vmail*)n->n.mln_Succ;
	}
	if( f )
		fclose( f );
	removekilled( mix );
	return(-1);
}

static long inhaltscstate;

static void domarkseen(void)
{
	struct mmail *mm=(struct mmail*)mix->maillist.lh_Head;
	long nc=0;
	int onlyread = prefs.flags2 & MDF2_ESCCLRONLYREAD;

	while(mm->n.mln_Succ)
	{
		if( mm->m.flags & MMF_UNSEEN )
		{
			if( !onlyread || ( mm->m.flags & MMF_READ ) )
			{
				mm->m.flags &= ~MMF_UNSEEN;
				mix->changed = 1;
			}
		}

		if(mm->m.flags & ( MMF_SHOW | MMF_UNSEEN ) )
			nc++;

		mm=(struct mmail*)mm->n.mln_Succ;
	}
	cmb->b.newmails = nc;
}

static int newinfold(struct mmail *m)
{
	while(m && m->n.mln_Succ)
	{
		if(m->m.flags&(MMF_SHOW|MMF_UNSEEN)) return(-1);
		if(m->firstbez) if(newinfold(m->firstbez)) return(-1);
		m=m->bezlink;
	}
	return(0);
}

/* nächste neue suchen */
static struct vmail *fnvm(struct vmail *vm)
{
	if( vm )
		vm=(struct vmail*)vm->n.mln_Succ;
	while(vm && vm->n.mln_Succ) {
		if(vm->m->m.flags&(MMF_UNSEEN|MMF_SHOW)||(vm->m->m.flags&MMF_FOLD&&newinfold(vm->m->firstbez)))
		{
			return(vm);
		}
		vm=(struct vmail*)vm->n.mln_Succ;
	}
	return(0);
}

static char *findnextboardwithnewmails( struct mbrett *mb )
{
	mb = ( struct mbrett * ) mb->n.ln_Succ;	
	while( mb && mb->n.ln_Succ )
	{
		if( mb->b.newmails && strncmp( mb->b.name, "/»", 2 ) )
			return( mb->b.name );
		mb = ( struct mbrett * ) mb->n.ln_Succ;
	}
	return( NULL );
}


static void domarknew(int mode)
{
	struct vmail *vm;
	int didchange = FALSE;

	if( mode )
	{
		vm=(struct vmail*)mlist.lh_Head;
		while(vm->n.mln_Succ)
		{
			if(vm->m->m.flags&(MMF_UNSEEN|MMF_SHOW))
				vm->sel=0xff;
			vm=(struct vmail*)vm->n.mln_Succ;
		}
		displayscroller();
		return;
	}

	/* naechste neue suchen */
	vm=(struct vmail*)GetEntry(&mlist,getscrollercurrent());

	if( ( prefs.flags2 & MDF2_AUTOCLRNEW ) && vm && ( vm->m->m.flags & MMF_UNSEEN ) )
	{
		vm->m->m.flags &= ~ MMF_UNSEEN;
		mix->changed = 1;
		didchange = TRUE;
	}

	vm=fnvm(vm);
	if(vm)
	{
		setscrollercurrent( GetEntryNum( &mlist, (struct Node*)vm ) );
		showcurrentitem(); 
		return;
	}

	if( didchange )
		displaycurrentline();

	/* Weiterspringen? */
	if( prefs.flags2 & MDF2_NEXTNEWBOARD )
	{
		if( prefs.flags2 & MDF2_NEXTNEWBOARDASK )
		{
			char *p = findnextboardwithnewmails( cmb );

			if( !p )
			{
				askreq( "Keine weiteren neuen Nachrichten\nin diesem Brett.\n\nKeine weiteren Bretter mit neuen Nachrichten.", "Ok" );
				return;
			}
			if( !askreq( "Keine weiteren neuen Nachrichten\nin diesem Brett. Wollen Sie in das\nnächste Brett mit neuen Nachrichten:\n%s\nspringen?",
				"Weiterspringen|Stopp", p
			))
			return;
		}

		donextnewboard = TRUE;
	}
	else displaybeep();
}

static void domarknextunread(void)
{
	struct vmail *vm;

	/* naechste neue suchen */
	vm=(struct vmail*)GetEntry( &mlist, getscrollercurrent() );
	vm=findnextunread(vm);
	if(vm)
	{
		setscrollercurrent(GetEntryNum(&mlist,(struct Node*)vm));
		showcurrentitem(); 
		return;
	}
	else
		displaybeep();
}

static void doinvsel(void)
{
	struct vmail *vm=(struct vmail*)mlist.lh_Head;

	while(vm->n.mln_Succ)
	{
		vm->sel ^= 0xff;
		vm=(struct vmail*)vm->n.mln_Succ;
	}

}

#define SR_DO 1
#define SR_CANCEL 2
#define SR_USEABS 3
#define SR_ABS 4
#define SR_USEBET 5
#define SR_BET 6
#define SR_USEIN 7
#define SR_IN 8
#define SR_INFO 9
#define SR_FG 10

void expandpattern( char *from, char *to )
{
	while( *from )
	{
		if( *from == '*' )
		{
			*to++ = '#';
			*to++ = '?';
		}
		else *to++ = *from;
		from++;
	}
	*to = 0;
}

static int matchmailcontents( struct msghandle *msg, char *pattern, BOOL matchheader, BOOL matchcomment )
{
	UBYTE maildata[ 1024 ];
	int rc = 0;
	int what = MC_DATA;

	if( matchcomment )
		what |= MC_COMMENT;
	if( matchheader )
		what |= MC_HEADER;

	msg_initread( msg, what );

	maildata[ 1023 ] = 0;
	while( msg_read( msg, maildata, 1023 ) )
	{
		rc |= astcsma( maildata, pattern );
	}

	msg_endread( msg );

	return( rc );
}

static void domarkbyabsender(struct IntuiMessage *im)
{
	struct vmail *vm=(struct vmail*)mlist.lh_Head;
	struct ogwin *ogw;
	struct Window *iw;
	static BYTE use_abs, use_bet, use_inhalt;
	int Done = FALSE;
	static char inhalt[ 128 ];
	char betpat[ 64 ];
	char abspat[ 64 ];
	char inpat[ 256 ];
	int counter = 0;
	int mark1, mark2, mark3;

	if( ISSHIFT( im ) )
	{
		while( vm->n.mln_Succ )
		{
			vm->sel = 0x0ff;
			vm = ( struct vmail * ) vm->n.mln_Succ;
		}
		return;
	}

	vm = ( struct vmail* ) GetEntry( &mlist, getscrollercurrent() );

	/*if(vm) strcpy(absender,vm->m->m.absender);*/

	ogw = ogreInitWindow( scr, 0, 0, "Nach Muster suchen" );
	ogreAddGroup( ogw, 0, OGFRAME_OUTLINE, " Muster " );
	ogreAddCheckbox( ogw, 0, 'b', "A_bsenderfilter?", SR_USEABS, use_abs );
	ogreAddString( ogw, 0, 'B', "", SR_ABS, vm ? vm->m->m.absender : "", 32, 32 );
	ogreAddCheckbox( ogw, 1, 't', " Be_treffilter?", SR_USEBET, use_bet );
	ogreAddString( ogw, 1, 'T', "", SR_BET, vm ? vm->m->m.betreff: "", 32, 32 );
	ogreAddCheckbox( ogw, 2, 'i', " _Inhaltsfilter?", SR_USEIN, use_inhalt );
	ogreAddString( ogw, 2, 'I', "", SR_IN, inhalt, 32, 128 );

	ogreAddGroup( ogw, 1 | OGGP_EXPANDSTRING, OGFRAME_OUTLINE, " Ergebnis " );
	ogreAddText( ogw, 0, "Nachricht:", SR_INFO, "", 32, 1 );
	ogreAddFuelGauge( ogw, 1, SR_FG, GetNumEntries( &mlist ) );

	ogreAddGroup( ogw, 2, OGFRAME_NONE, NULL );
	ogreAddButton( ogw, 0 | OGB_ONENTER, 's', "_Suche starten", SR_DO );
	ogreAddHelp( ogw, 0 );
	ogreAddButton( ogw, 0 | OGB_ONESC, 'a', "_Abbruch", SR_CANCEL );

	iw = ogreOpenWindow( ogw );
	if( !iw )
	{
		return;
	}

	while( !Done )
	{
		use_abs = ogreValue( ogw, SR_USEABS );
		use_bet = ogreValue( ogw, SR_USEBET );
		use_inhalt = ogreValue( ogw, SR_USEIN );

		ogreEnable( ogw, use_abs, SR_ABS, 0 );
		ogreEnable( ogw, use_bet, SR_BET, 0 );
		ogreEnable( ogw, use_inhalt, SR_IN, 0 );

		ogreEnable( ogw, use_abs || use_bet || use_inhalt, SR_DO, 0 );

		im = ogreWaitIM( ogw );

		if( im->Class == IDCMP_GADGETHELP)
			showguidenum( "brettsuchreq_gads", im->Code );
		else if( im->Class == GADGETUP )
		{
			switch( im->Code )
			{
				case SR_DO:
					Done = 2;
					break;

				case SR_CANCEL:
					Done = 1;
					break;
			}
		}

		ogreIMReply( ogw, im );
	}

	if( Done == 2 )
	{
		vm = (struct vmail*)mlist.lh_Head;

		ogreEnable( ogw, FALSE, SR_DO, SR_ABS, SR_BET, SR_IN, SR_USEABS, SR_USEBET, SR_USEIN, 0 );
		ogreCopyStringValue( ogw, SR_IN, inhalt );

		expandpattern( ogreStringValue( ogw, SR_ABS ), abspat );
		expandpattern( ogreStringValue( ogw, SR_BET ), betpat );
		expandpattern( ogreStringValue( ogw, SR_IN ), inpat );

		strcat( abspat, "#?" );
		strcat( betpat, "#?" );
		strcat( inpat, "#?" );
		strins( inpat, "#?" );

		Done = FALSE;

		while( !Done && vm->n.mln_Succ )
		{
			if( im = ogreIM( ogw ) )
			{
				if( ( im->Class == IDCMP_GADGETUP )	&& ( im->Code == SR_CANCEL ) )
					Done = TRUE;
				ogreIMReply( ogw, im );
			}

			ogreSetStringValue( ogw, SR_INFO, vm->m->m.betreff );
			mark1 = mark2 = mark3 = FALSE;
			if( use_abs )
			{
				if( astcsma( vm->m->m.absender, abspat ) )
					mark1 = TRUE;
			}
			else
				mark1 = TRUE;

			if( use_bet )
			{
				if( astcsma( vm->m->m.betreff, betpat ) )
					mark2 = TRUE;
			}
			else
				mark2 = TRUE;

			if( use_inhalt )
			{
				struct msghandle *msg = msg_openv( vm );
				if( matchmailcontents( msg, inpat, 0, 0 ) )
					mark3 = TRUE;
				msg_close( msg );
			}
			else
				mark3 = TRUE;

			if( mark1 && mark2 && mark3 )
				vm->sel = 0xff;
			vm = ( struct vmail * ) vm->n.mln_Succ;
			ogreSetValue( ogw, SR_FG, counter++ );
		}
	}

	ogreExitWindow( ogw );

}

static struct vmail *findfup2(struct IntuiMessage *im,struct vmail *vm)
{
	struct mmail *m;

	if(!vm) { displaybeep(); return(0); }
	m=vm->m;

	if((im->Code==0x4e||im->Code==0x2f) && !ISSHIFT(im)) {
		vm=findvmail(m->bezlink);
		return(vm);
	}
	else if((im->Code==0x4e||im->Code==0x2f) && ISSHIFT(im)) {
		vm=findvmail(m->firstbez);
		return(vm);
	}
	else if((im->Code==0x4f||im->Code==0x2d) && !ISSHIFT(im)) {
		while(vm->n.mln_Pred && vm->m->bezlink!=m) vm=(struct vmail*)vm->n.mln_Pred;
		if(!vm->n.mln_Pred || vm->m->bezlink!=m) vm=0;
		return(vm);
	}
	else if((im->Code==0x4f||im->Code==0x2d) && ISSHIFT(im)) {
		vm=findvmail(m->parent);
		return(vm);
	}
}

static void findfup(struct IntuiMessage *im)
{
	struct vmail *vm=(struct vmail*)GetEntry(&mlist,getscrollercurrent());

	vm=findfup2(im,vm);
	if(vm) {
		int rc=GetEntryNum(&mlist,(struct Node*)vm);
		setscrollercurrent(rc);
		showcurrentitem();
	}
}

static void doarcmail( struct vmail *n )
{
	struct mbrett *mb=findbrett("/»ARCHIV",0);

	storemail2ix( &n->m->m, mb, NULL );
}

static void doarcmsg(void)
{
	iteratemsglist( doarcmail );
}

static void addusertouserlist(char *user,char *teflon, char *post, char *pgpid, BOOL pgp )
{
	char username[128];
	char realname[40];
	struct user u,u2;
	FILE *f;
	char *p,*p2;

	pushhomedir();

	realname[0]=realname[39]=0;
	username[127]=0;
	strncpy(username,user,127);
	p=strchr(username,' ');
	if(p) {
		*p++=0;
		p=strchr(p,'(');
		if(p) {
			*p++=0;
			p=stpblk(p);
			p2=strchr(p,')');
			if(p2) *p2=0;
			strncpy(realname,p,39);
		}
	}

	if(!realname[0]) strncpy(realname,username,39);

	memset(&u,0,sizeof(struct user));
	strcpy(u.net,username);
	strcpy(u.realname,realname);
	if( teflon )
		strncpy(u.telefon,teflon,31);
	if( post ) 
		strncpy( u.adresse, post, 63 );
	if( pgpid )
		strncpy( u.pgp_id, pgpid, 39 );

	//if( pgp && pgpavail )
	//	u.flags |= UF_PGP;

	f=fopen("microdot.userdb","r");
	if(f) {
		fsetbuf(f,8192);
		while(fread(&u2,sizeof(struct user),1,f)==1) {
			if(!stricmp(u2.net,username))
			{
				fclose(f);
				displaybeep();
				popdir();
				return;
			}
		}
		fclose(f);
	}
	f=fopen("microdot.userdb","a+");
	popdir();
	if(!f)
	{
		displaybeep();
		return;
	}
	fwrite(&u,sizeof(struct user),1,f);
	fclose(f);
}

static void dosaveuser(struct vmail *n)
{
	struct header *hl,*hl2, *hl3;
	struct hlist *hlist;
	struct msghandle *msg;
	int usepgp;

	msg = msg_openv( n );
	if( !msg )
		return;

	usepgp = n->m->m.flags & ( MMF_PGPSIGNED | MMF_PGPCRYPT );

	hlist = msg_loadheader( msg );
	msg_close( msg );
	hl = hl_findheader( hlist, "ABS");
	if(!hl || !hl->data || !hl->data[0])
	{
		hl_freeheader( hlist );
		displaybeep();
		return;
	}

	hl2 = hl_findheader( hlist, "TELEFON");
	hl3 = hl_findheader( hlist, "POST" );
	if( !usepgp )
	{
		if( hl_findheader( hlist, "PGP-KEY-AVAIL" ) || hl_findheader( hlist, "PGP-PUBLIC-KEY" ) )
			usepgp = TRUE;
	}

	addusertouserlist(
		hl->data,
		(hl2&&hl2->data)?hl2->data:NULL,
		(hl3&&hl3->data)?hl3->data:NULL,
		NULL,
		usepgp ? TRUE : FALSE
	);

	hl_freeheader( hlist );
}

static void dokilluser(struct vmail *n)
{
	struct header *hl;
	FILE *f;
	int rc;

	struct hlist *hlist;
	struct msghandle *msg;

	msg = msg_openv( n );
	if( !msg )
		return;

	hlist = msg_loadheader( msg );
	msg_close( msg );
	hl = hl_findheader( hlist, "ABS");
	if(!hl || !hl->data || !hl->data[0])
	{
		hl_freeheader( hlist );
		displaybeep();
		return;
	}

	rc = askreq( "Wollen Sie User\n%s\nwirklich filtern?\nAlle Nachrichten mit diesem Absender\nwerden dann in Zukunft nicht mehr\neinsortiert, sondern sofort gelöscht.", 
		"User filtern|Abbruch",
		hl->data
	);

	if( !rc )
	{
		hl_freeheader( hlist );
		return;
	}

	f = fopen( "microdot.killuser", "a" );
	if( !f )
		f = fopen( "microdot.killuser", "w" );
	if( !f )
	{
		displaybeep();
		hl_freeheader( hlist );
		return;
	}
	fprintf( f, "%s\n", hl->data );
	fclose( f );
	hl_freeheader( hlist );
}

static void dosaveusers(void)
{
	struct vmail *n=(struct vmail*)mlist.lh_Head;
	int count=0;

	if(!mmcount)
	{
		n=(struct vmail*)GetEntry(&mlist,getscrollercurrent());
		dosaveuser(n);
		return;
	}
	savesel();
	while(n->n.mln_Succ) {
		if(n->sel) {
			dosaveuser(n);
			n->sel=0;
			count++;
		}
		n=(struct vmail*)n->n.mln_Succ;
	}
	preport(1,1,"%lD User gespeichert.",count);
}

#define GID_LV 1
#define GID_EMPS 2
#define GID_LVNEU 3
#define GID_LVBRETT 4
#define GID_LVUSER 5
#define GID_LVLOESCH 6
#define GID_SEND 7
#define GID_CANCEL 8

static char ** getemplist( char *title )
{
	struct IntuiMessage *im;
	struct ogwin *ogw;
	struct ogrevn *vn;
	struct Window *iw;
	int Done = FALSE;
	int isediting = -1;
	int c;
	int size;
	char **emp = NULL;
	char *store, *p;
	APTR rtwinlock;

	ogw = ogreInitWindow( scr, WFLG_RMBTRAP, 0, title );

	ogreAddGroup( ogw, 0 | OGGP_EXPANDSTRING , OGFRAME_OUTLINE, " Empfänger " );
	ogreAddList( ogw, 0, 0xff, NULL, GID_LV, 40, 8, 0, NULL );
	ogreLVInit( ogw, GID_LV );

	ogreAddString( ogw, 1, '\n', NULL, GID_EMPS, NULL, 40, 256 | OGSF_NONEXTACT );
	ogreAddButton( ogw, 2, 'n', "_Neu", GID_LVNEU );
	ogreAddButton( ogw, 2, 'b', "_Brett", GID_LVBRETT );
	ogreAddButton( ogw, 2, 'u', "_UserIn", GID_LVUSER );
	ogreAddButton( ogw, 2, 'l', "_Löschen", GID_LVLOESCH );

	ogreAddGroup( ogw, 1 | OGGP_EXPANDSTRING, OGFRAME_NONE, NULL );

	ogreAddButton( ogw, 0 | OGB_ONENTER, 'v', "_Verschicken", GID_SEND );
	ogreAddHelp( ogw, 0 );
	ogreAddButton( ogw, 0 | OGB_ONESC, 'a', "_Abbruch", GID_CANCEL );

	iw = ogreOpenWindow( ogw );
	if( !iw )
	{
		return( 0 );
	}

	while( !Done )
	{
		ogreEnable( ogw, isediting >= 0, GID_EMPS, GID_LVLOESCH, 0 );
		mWaitPort( iw->UserPort );
		while( ( im = ogreIM( ogw ) ) )
		{
			if( im->Class == IDCMP_GADGETHELP)
				showguidenum( "getemps_gads", im->Code );
			else if( im->Class == GADGETUP )
			{
				switch( im->Code )
				{
					case GID_EMPS:
						if( isediting >= 0 )
						{
							ogreLVSelect( ogw, GID_LV, -1 );
							ogreLVSetEntry( ogw, GID_LV, isediting, ogreStringValue( ogw, GID_EMPS ), 2 );
							ogreLVRefresh( ogw, GID_LV );					
							isediting = -1;
							ogreSetStringValue( ogw, GID_EMPS, "" );
						}
						break;

					case GID_LV:
						isediting = ogreValue( ogw, GID_LV );
						vn = ogreLVGetEntry( ogw, GID_LV, isediting );
						if( vn )
						{
							ogreEnable( ogw, TRUE, GID_EMPS, 0 );
							ogreSetStringValue( ogw, GID_EMPS, vn->txt );
							if( im->Qualifier )
								ogreActivate( ogw, GID_EMPS );
						}
						break;

					case GID_LVLOESCH:
						if( isediting >= 0 )
						{
							ogreLVRemEntry( ogw, GID_LV, isediting );
							ogreLVRefresh( ogw, GID_LV );
							isediting = -1;
							ogreSetStringValue( ogw, GID_EMPS, "" );
						}
						break;

					case GID_LVBRETT:
						rtwinlock = rtLockWindow( iw );
						p = dobrettreq();
						rtUnlockWindow( iw, rtwinlock );
						if( p )
							goto addent;
						break;
					
					case GID_LVUSER:
						rtwinlock = rtLockWindow( iw );
						p = douserreq();
						rtUnlockWindow( iw, rtwinlock );
						if( !p )
							break;
					  addent:
						ogreLVAddEntry( ogw, GID_LV, p, 2, 0 );
						isediting = -1;
						ogreLVSelect( ogw, GID_LV, -1 );
						ogreLVRefresh( ogw, GID_LV );
						break;

					case GID_LVNEU:
						isediting = ogreLVAddEntry( ogw, GID_LV, "", 1, 0 );
						ogreLVRefresh( ogw, GID_LV );
						ogreSetStringValue( ogw, GID_EMPS, "" );
						ogreActivate( ogw, GID_EMPS );
						break;

					case GID_SEND:
						Done = 2;
						break;

					case GID_CANCEL:
						Done = 1;
						break;
				}
			}
		}
	}

	if( Done == 2 )
	{
		/* Calc size */
		for( size = c = 0; vn = ogreLVGetEntry( ogw, GID_LV, c ); c++ )
		{
			size += 5 + strlen( vn->txt );
		}
		emp = myAllocVec( size + 4, MEMF_CLEAR );
		if( emp )
		{
			store = ( char * ) &emp[ c + 1 ];
			for( c = 0; vn = ogreLVGetEntry( ogw, GID_LV, c ); c++ )
			{
				emp[ c ] = store;
				strcpy( store, vn->txt );
				store = strchr( store, 0 ) + 1;
			}
		}
	}

	ogreExitWindow( ogw );
	return( emp );
}

extern int sendwinauto;
static int doweiter(struct IntuiMessage *im)
{
	struct vmail *n=(struct vmail*)mlist.lh_Head;
	int rc, rv = 0;
	char **emplist;
	char buffer[ 128 ];

	if(!mmcount)
	{
		n=(struct vmail*)GetEntry(&mlist,getscrollercurrent());
		if(n)
			rv = doweitermail(n);
		return( rv );
	}

	rc = askreq( "Weiterleiten:\nInsgesamt %lD Nachrichten markiert",
		"_Einzeln weiterleiten|_Gesammelt weiterleiten|Gesammelt _ohne Nachfrage|Abbruch",
		mmcount
	);

	if( !rc )
		return( 0 );

	if( rc == 1 )
	{
		savesel();
		while(n->n.mln_Succ)
		{
			if(n->sel)
			{
				rv |= doweitermail(n);
				n->sel=0;
			}
			n=(struct vmail*)n->n.mln_Succ;
		}
		return( rv );
	}

	/* Gesammelt weiterleiten */

	sprintf( buffer, "%lD Nachrichten weiterleiten", mmcount );

	emplist = getemplist( buffer );

	if( !emplist )
		return( 0 );

	while(n->n.mln_Succ)
	{
		savesel();
		if(n->sel)
		{
			if( rc == 3 )
				sendwinauto = TRUE;
			rv |= doweiterquiet( emplist, n );
			n->sel=0;
		}
		n=(struct vmail*)n->n.mln_Succ;
	}

	myFreeVec( emplist );

	return( rv );
}

extern int ml_kb, ml_date;
static char * makekb( int val )
{
	static char mem[ 32 ];

	sprintf( mem, "%lD", val );
	if( strlen( mem ) <= ml_kb )
		return( mem );

	sprintf(mem, "%lDK", ( val + 1023 ) / 1024 );
	if( strlen( mem ) <= ml_kb )
		return( mem );

	sprintf(mem, "%lDM", ( val + ( 1024 * 1024 - 1 ) ) / ( 1024 * 1024 ) );
	return( mem );
}

static void __inline makevnode( struct vmail *n )
{
	char x[ 8 ], *p;
	int plen;

	utunpk( n->m->m.time, x );
	n->date[ 0 ] = '0' + x[ 2 ] / 10;
	n->date[ 1 ] = '0' + x[ 2 ] % 10;
	n->date[ 2 ] = '.';
	n->date[ 3 ] = '0' + x[ 1 ] / 10;
	n->date[ 4 ] = '0' + x[ 1 ] % 10;

	//sprintf( n->date, "%02ld.%02ld", x[ 2 ], x[ 1 ] );
	if( ml_date == 11 )
	{
		utunpk( n->m->m.incomtime, x );
		//sprintf( &n->date[ 5 ], "\005%02ld.%02ld", x[ 2 ], x[ 1 ] );
		n->date[ 5 ] = 5;
		n->date[ 6 ] = '0' + x[ 2 ] / 10;
		n->date[ 7 ] = '0' + x[ 2 ] % 10;
		n->date[ 8 ] = '.';
		n->date[ 9 ] = '0' + x[ 1 ] / 10;
		n->date[ 10 ] = '0' + x[ 1 ] % 10;
		n->date[ 11 ] = 0;
	}
	else
		n->date[ 5 ] = 0;

	memset( n->kb, 32, 12 );
	p = makekb( n->m->m.maillen );
	plen = strlen( p );
	memcpy( &n->kb[ ml_kb - plen ], p, plen );
}

void makevnodemlist( struct List *what )
{
	struct vmail *n = ( struct vmail * ) what->lh_Head;

	while( n->n.mln_Succ )
	{
		makevnode( n );
		n = ( struct vmail * ) n->n.mln_Succ;
	}
}


static void attachtree(struct List *to,struct mmail *parent,UBYTE indent,UBYTE *indentspace)
{
	struct vmail *n;

	/* gekillt */
	if( parent->m.flags & MMF_KILL )
		return;
#if 0
	if( ( prefs.flags & MDF_HIDEDEL ) && ( parent->m.flags & MMF_DEL ) )
		return;
#endif

	/* Eine Muttermehl */
	n = LibAllocPooled( mlistpool, sizeof( struct vmail ) );
	if( !n )
	{
		displaybeep();
		return;
	}
	n->m = parent;
	n->indent = indent;
//	makemmailhash( parent );

	makevnode( n );

	// Display-Werte eintragen

	if( indent )
	{
		if( parent->bezlink)
			indentspace[ indent - 1 ] = 1;
		else
			indentspace[ indent - 1 ] = 4;
	}
	memcpy( n->indentspace, indentspace, 63 );
	AddTail( to, ( struct Node * ) n );
	/* Bezuege auf diese Mail? */
	if( parent->firstbez && !( n->m->m.flags & MMF_FOLD ) )
	{ 
		if(parent->bezlink) indentspace[indent-1]=2;
		else indentspace[indent-1]=32;
		indentspace[indent]=4;
		attachtree(to,parent->firstbez,indent+1,indentspace);
	}
	if( parent->bezlink )
	{
		attachtree( to, parent->bezlink, indent, indentspace );
	}
	indentspace[ indent ] = 0;
}

static char *skipre( char *txt )
{
	txt = stpblk( txt );
	if( !strnicmp( txt, "re", 2 ) )
	{
		char *newtxt = txt + 2;
		if( *newtxt == '^' )
		{
			newtxt++;
			while( isdigit( *newtxt ) )
				newtxt++;
		}
		if( *newtxt == ':' )
		{
			return( skipre( newtxt + 1 ) );
		}
	}
	return( txt );
}

static int __stdargs sortmcmpf(struct mmail **s1,struct mmail **s2)
{
	int rc;
	char *p1=(*s1)->m.betreff;
	char *p2=(*s2)->m.betreff;

	rc = strnicmp( &p1[ (*s1)->reoffset ], &p2[ (*s2)->reoffset ], min( strlen( p1 ), strlen( p2 ) ) );
	if( !rc )
		rc = ((*s1)->m.time)-((*s2)->m.time);
	return( rc );
}

static int __stdargs sortmcmpf_date( struct mmail **s1, struct mmail **s2 )
{
	int rc;

	rc=((*s1)->m.time)-((*s2)->m.time);
	if( !rc )
	{
		char *p1=(*s1)->m.betreff;
		char *p2=(*s2)->m.betreff;
		rc = strnicmp( &p1[ (*s1)->reoffset ], &p2[ (*s2)->reoffset ], min( strlen( p1 ), strlen( p2 ) ) );
	}
	return( rc );
}

void makemlist(struct List *from,struct List *to)
{
	int c,d,count;
	struct mmail **array,*n=(struct mmail*)from->lh_Head;
	char indentspace[ 256 ];

	if( wrotenewmails )
	{
		newmailptr = (struct mmail *) from->lh_TailPred;
	}

	mlistpool = LibCreatePool( MEMF_CLEAR, 8192, 2048 );

	memset( indentspace, 0, 256 );
	NewList(to);
	count=0;
	while( n->n.mln_Succ )
	{
		n->reoffset = ( skipre( n->m.betreff ) ) - n->m.betreff;
		if( !n->parent ) count++;
		n=( struct mmail * ) n->n.mln_Succ;
	}
	if( !count )
		return;
	array=myAllocVec( 4*count, 0 );
	if( !array )
	{
		displaybeep();
		return;
	}
	n=(struct mmail*)from->lh_Head;
	for(c=d=0; d<count; c++)
	{
		if( !n->parent )
			array[d++]=n;
		n=(struct mmail*)n->n.mln_Succ;
	}
	qsort(array,count,4,(prefs.flags&MDF_SORTDATE)?sortmcmpf_date:sortmcmpf);
	for(c=0; c<count; c++) 
		attachtree( to, array[ c ], 0, indentspace );
	myFreeVec( array );
}

static void dodelfunc( struct vmail * n )
{
	n->m->m.flags |= MMF_DEL;
	if( prefs.flags2 & MDF2_HARDDEL )
		n->m->m.flags &= ~MMF_ARCHIVE;
}

static void dodelmsg(void)
{
	int oldmmcount = mmcount;

	iteratemsglist( dodelfunc );

	if( oldmmcount )
	{
		displayscroller();
	}
	else
	{
		displaycurrentline();
		incscroller();
	}

}

static void doholdmsg(int set)
{
	struct vmail *n=(struct vmail*)mlist.lh_Head;

	mix->changed=1;
	if(!mmcount)
	{
		n=(struct vmail*)GetEntry(&mlist,getscrollercurrent());
		if(!set) n->m->m.flags|=MMF_ARCHIVE;
		else n->m->m.flags&=~MMF_ARCHIVE;

		displaycurrentline();
		incscroller();
	}
	else
	{
		savesel();
		while(n->n.mln_Succ)
		{
			if(n->sel)
			{
				if(!set) n->m->m.flags|=MMF_ARCHIVE;
				else n->m->m.flags&=~MMF_ARCHIVE;
				n->sel=0;
			}
			n=(struct vmail*)n->n.mln_Succ;
		}
		displayscroller();
	}
}

static void dosetunread( struct vmail * n )
{
	n->m->m.flags &= ~MMF_READ;
}


static void dosetreadmsg(int set)
{
	struct vmail *n=(struct vmail*)mlist.lh_Head;
	int oldmmcount = mmcount;

	mix->changed=1;
	if(set)
	{
		while(n->n.mln_Succ)
		{
			if(!(n->m->m.flags&MMF_READ)) n->sel=0xff;
			n=(struct vmail*)n->n.mln_Succ;
		}
		displayscroller();
		return;
	}

	iteratemsglist( dosetunread );

	if( oldmmcount )
	{
		displayscroller();
	}
	else
	{
		displaycurrentline();
		incscroller();
	}
}


/* Nachrichten auf Gelesen setzen */

static void dosetread( struct vmail *n )
{
	n->m->m.flags |= MMF_READ;
}

static void dosetreadsel( void )
{
	int oldmmcount = mmcount;

	iteratemsglist( dosetread );

	if( oldmmcount )
	{
		displayscroller();
	}
	else
	{
		displaycurrentline();
		incscroller();
	}

}

static void dosetnewmsg( void )
{
	struct vmail *n=(struct vmail*)mlist.lh_Head;

	mix->changed=1;
	if(!mmcount)
	{
		n=(struct vmail*)GetEntry(&mlist,getscrollercurrent());
		if(n)
		{
			n->m->m.flags |= MMF_SHOW;
			displaycurrentline();
			incscroller();
		}
		return;
	}
	while(n->n.mln_Succ)
	{
		if(n->sel) n->m->m.flags |= MMF_SHOW;
		n=(struct vmail*)n->n.mln_Succ;
	}
	displayscroller();
}

static void doundelfunc( struct vmail * n )
{
	n->m->m.flags &= ~MMF_DEL;
}


static void doundelmsg(void)
{
	int oldmmcount = mmcount;

	iteratemsglist( doundelfunc );

	if( oldmmcount )
	{
		displayscroller();
	}
	else
	{
		displaycurrentline();
		incscroller();
	}

}

static void *dlistpool;
static void initdlist(struct List *l)
{
	NewList( l );
	dlistpool = LibCreatePool( MEMF_CLEAR, 8192, 4096 );
}

// Puren Text schreiben, aber mit Style-Konvertierung

static void __stdargs addd(struct List *to,int b,char *txt,...)
{
	char buff[ 8192 ];
	struct dnode *new;
	int x,x2,offs=0;

	dofmtextabs(buff,txt,(void*)(((long)&txt)+4));
	x=strlen(buff);

	if(!x)
	{
		new = LibAllocPooled( dlistpool, sizeof( struct dnode ) );
		if( !new )
			return;
		new->txt = "";
		AddTail( to, ( struct Node * ) new );
		return;
	}		

	while( x )
	{
		x2 = x;
		if( x2 > screencols )
			x2 = screencols;
		x -= x2;
		new = LibAllocPooled ( dlistpool, sizeof(struct dnode) );
		if( !new )
			return;
		new->txt = LibAllocPooled( dlistpool, x2 + 1 );
		new->sty = LibAllocPooled( dlistpool, x2 );

		new->bold = b;

		if( b == 2 || ( prefs.flags & MDF_NOREADERSTYLES ) )
		{
			new->len  = x2;
			strncpy( new->txt, &buff[ offs ], x2 );
		}
		else
		{
			stylenode( &buff[ offs ], x2, new->txt, new->sty );
			new->len = strlen( new->txt );
		}

		AddTail(to,(struct Node*)new);
		offs += x2;
	}
}

static int getquotelevel( char *txt )
{
	int c;
	char *p = txt;

	txt = stpblk( txt );
	if( txt - p > 12 )
		return( 0 );

	if( *txt == ':' && isspace( txt[ 1 ] ) )
	{
		return( getquotelevel( &txt[ 2 ] ) + 1 );
	}
	if( *txt == '|' )
	{
		if( isspace( txt[ 1 ] ) || txt[ 1 ] == '>' )
			return( getquotelevel( &txt[ 2 ] ) + 1 );
	}

	for( c = 0; c < 3; c++ )
	{
		if( !isalnum( *txt ) )
			break;
		txt++;
	}
	if( *txt == '>' || *txt == ']' )
		return( getquotelevel( &txt[ 1 ] ) + 1 );
	else
		return( 0 );
}

static void __stdargs addqt( struct List *to, int style, int showquote, char *txt )
{
	struct dnode *new;
	int x,x2,offs = 0;
	int b = 0;
	char buffer[ 2048 ];

	x = strlen( txt );

	if( !x )
	{
		new = LibAllocPooled( dlistpool, sizeof( struct dnode ) );
		new->txt = "";
		AddTail( to, ( struct Node * ) new );
		return;
	}		

	expandtabs( txt, buffer, prefs.reader_tabsize );

	txt = buffer;
	x = strlen( txt );

	if( showquote )
	{
		b = getquotelevel( txt );
		if( b > 1 )
			b++;	
	}
	else
		b = 0;
#if 0
	p = stpblk( txt );
	if( ql && !strncmp(p,quoteid,ql) )
		b=1;
	else if((*p=='>'||p[1]=='>'||p[2]=='>'))
		b=1;
#endif

	while( x )
	{
		x2 = x;
		if( x2 > screencols )
			x2 = screencols;
		x -= x2;
		new = LibAllocPooled ( dlistpool, sizeof( struct dnode ) );
		if( !new )
			break;

		new->txt = LibAllocPooled( dlistpool, x2 + 1 );
		new->sty = LibAllocPooled( dlistpool, x2 );

		new->bold = b;

		if( !style )
		{
			new->len  = x2;
			strncpy( new->txt, &txt[ offs ], x2 );
		}
		else
		{
			stylenode( &txt[ offs ], x2, new->txt, new->sty );
			new->len = strlen( new->txt );
		}

		AddTail(to,(struct Node*)new);
		offs += x2;
	}
}

static void freedlist(void)
{
	if(dlistpool)
	{
		LibDeletePool(dlistpool);
		dlistpool=0;
	}
}

/*static int cmpstr(char *s1,char *s2)
{
	int c;

	for(c=0; s1[c]; c++) {
		if(s1[c]!=s2[c]) return(c);
	}
	return(0);
}*/


/*static void quotedlist(struct List *l,char *quoteid)
{
	struct dnode *n=(struct dnode*)l->lh_Head;
	char *p;
	int ql;

	ql=strlen(quoteid);

	while(n->n.mln_Succ)
	{
		p=stpblk(n->txt);
		if( ql && !strncmp(p,quoteid,ql) )
			n->bold=1;
		else if((*p=='>'||p[1]=='>'||p[2]=='>'))
			n->bold=1;
		n=(struct dnode*)n->n.mln_Succ;
	}
}
*/

static ULONG lastmsgcs;

static void procheader(struct List *l,char *header,char *p)
{
	int c;
	char headmem[32];

	header = translateheader( header, p );
	if( datmem[0] )
		p = datmem;

	strncpy(headmem,header,18);
	headmem[18]=0;
	for(c=strlen(headmem); c<18; headmem[c++]='.');

	addd(l,2,"%s: %s",headmem,p);
}

static void getmailinfo(char *mid,char *to)
{
	ULONG crc;
	struct mmail *m=(struct mmail*)mix->maillist.lh_Head;

	*to=0;
	crc=crc32(mid,strlen(mid));

	while(m->n.mln_Succ)
	{
		if(m->m.midcrc==crc) goto foundcrc;
		m=(struct mmail*)m->n.mln_Succ;
	}
	return;
foundcrc:
	if( !strncmp( m->m.absender, "an ", 3 ) )
		sprintf(to,"%s, \"%s\"",
			m->m.absender,m->m.betreff);
	else
		sprintf(to,"von %s, \"%s\"",
			m->m.absender,m->m.betreff);
}

extern int brettreqshowpmboards;
static int docopymail( struct vmail * n )
{
	char *dest;
	struct mbrett *mb;
	struct mail m;

	brettreqshowpmboards = TRUE;
	dest = dobrettreqtitle( "Nachricht kopieren: Zielbrett auswählen" );
	brettreqshowpmboards = FALSE;
	if( !dest )
		return( 0 );

	mb = findbrett( dest, 0 );
	if( !mb )
	{
		askreq( "Brett %s unbekannt.\n", "Abbruch", dest );
		return( 0 );
	}

	m = n->m->m;
	//m.absenderreal[ 0 ] = 0;
	storemail2ix( &m, mb, NULL );

	return( -1 );
}


static void docopymails( void )
{
	struct vmail *n = ( struct vmail * ) mlist.lh_Head;
	char title[ 64 ];
	char *dest;
	struct mbrett *mb;

	mix->changed=1;

	if(!mmcount)
	{
		n=(struct vmail*)GetEntry(&mlist,getscrollercurrent());
		if( n )
		{
			docopymail( n );
			incscroller();
		}
	}
	else
	{
		savesel();

		sprintf( title, "%lD Nachrichten kopieren: Zielbrett auswählen", mmcount );
		brettreqshowpmboards = TRUE;
		dest = dobrettreqtitle( title );
		brettreqshowpmboards = FALSE;
		if( !dest )
			return;

		mb = findbrett( dest, 0 );
		if( !mb )
		{
			askreq( "Brett %s unbekannt.\n", "Abbruch" );
			return;
		}

		while( n->n.mln_Succ )
		{
			if( n->sel )
			{
				storemail2ix( &n->m->m, mb, NULL );
				n->sel = 0;
			}
			n=(struct vmail*)n->n.mln_Succ;
		}
	}
	displayscroller();
}

#define XBSIZE 512
static int readmail(struct vmail *n)
{
	struct List tlist;
	struct vmail *tmv;
	struct mmail *m;
	char path[512];
	int Done, redo = FALSE, donttouchflags = FALSE;
	struct IntuiMessage im,*mp;
	int rc;
	void *scs=0;
	long rt;
	struct header *hl;
	char *p;
	USHORT oldflags;
	ULONG sigs, wsig;
	struct msghandle *msg;
	struct hlist *hlist;
	int redoasc;
	int redotop = 0;

	execrexx( "Reader" );

	OffMenu(w,SHIFTMENU(0)|SHIFTITEM(NOITEM));

	for(rc=0; rc<12; rc++)
		OffMenu(w,SHIFTMENU(3)|SHIFTITEM(rc));

	OffMenu(w,SHIFTMENU(4)|SHIFTITEM(NOITEM));
	OffMenu(w,SHIFTMENU(5)|SHIFTITEM(NOITEM));
	OffMenu(w,SHIFTMENU(6)|SHIFTITEM(NOITEM));

	OffMenu(w,SHIFTMENU(2)|SHIFTITEM(0));

	scs = pushscs();

redo:
	redoasc = FALSE;
	initdlist( &tlist );
	oldflags = prefs.flags & ( MDF_SHOWALL | MDF_GADGETS | MDF_NOREADERSTYLES );
	if( !n )
	{
		displaybeep();
		displayscroller();
		ClearPointer(w);
		goto xit;
	}

	currentreadermail = n;

	m=n->m;
	lastmailnum = GetEntryNum( &mlist, (struct Node*) n );
	cmpid = n->m->m.midcrc;

	if( !donttouchflags )
	{
		if( ( ( ! ( m->m.flags & MMF_READ ) || ( m->m.flags&MMF_SHOW ) ) ) )
		{
			m->m.flags|=MMF_READ;
			m->m.flags&=~MMF_SHOW;
			mix->changed=1;
		}

		if( ( prefs.flags2 & MDF2_AUTOCLRNEW ) && ( m->m.flags & MMF_UNSEEN ) )
		{
			m->m.flags &= ~MMF_UNSEEN;
			mix->changed = 1;
		}
	}
	donttouchflags = FALSE;

	redo = Done = FALSE;

	msg = msg_openv( n );
	if( !msg )
	{
		displayscroller();
		ClearPointer(w);
		goto xit;
	}

	/* header erstellen */
	hlist = msg_loadheader( msg );

	if( prefs.flags & MDF_SHOWALL )
	{
		hl = hl_findheader( hlist, NULL );
		while( hl->n.mln_Succ )
		{
			procheader(&tlist,hl->head,hl->data);
			hl=(struct header*)hl->n.mln_Succ;
		}
	}
	else
	{
		/*
			 Standard-Header
		*/
		hl=hl_findheader(hlist,"ABS");
		if(hl) addd(&tlist,2,"Absender..........: %s",hl->data);

		path[0]=0;
		hl=hl_findheader(hlist,"EMP");
		while(hl)
		{
			if( strlen( path ) + strlen( hl->data ) > XBSIZE - 20 )
			{
				strcat( path, "...  " );
				break;
			}

			strcat(path,hl->data);
			strcat(path,", ");
			hl=hl_findnextheader(hl);
		}
		if(path[0])
		{
			path[strlen(path)-2]=0;
			addd(&tlist,2,"Empfänger.........: %s",path);
		}


		path[0]=0;
		hl=hl_findheader(hlist,"KOP");
		while(hl)
		{
			if( strlen( path ) + strlen( hl->data ) > XBSIZE - 20 )
			{
				strcat( path, "...  " );
				break;
			}

			strcat(path,hl->data);
			strcat(path,", ");
			hl=hl_findnextheader(hl);
		}
		if(path[0])
		{
			path[strlen(path)-2]=0;
			addd(&tlist,2,"Kopieempfänger....: %s",path);
		}


		hl=hl_findheader(hlist,"OAB");
		if(hl) addd(&tlist,2,"Originalabsender..: %s",hl->data);

		hl=hl_findheader(hlist,"WAB");
		if(hl) addd(&tlist,2,"Weiterleitungsabs.: %s",hl->data);

		path[0]=0;
		hl=hl_findheader(hlist,"OEM");
		while(hl)
		{
			if( strlen( path ) + strlen( hl->data ) > XBSIZE - 20 )
			{
				strcat( path, "...  " );
				break;
			}
			strcat( path, hl->data );
			strcat( path, ", " );
			hl=hl_findnextheader(hl);
		}
		if(path[0])
		{
			path[strlen(path)-2]=0;
			addd(&tlist,2,"Orignalempfänger..: %s",path);
		}
	
		/* Status */
		path[0]=0;
		hl=hl_findheader(hlist,"TYP");
		if(hl) sprintf(path,"%s ",hl->data);
		hl=hl_findheader(hlist,"STAT");
		while(hl)
		{
			if( strlen( path ) + strlen( hl->data ) > XBSIZE - 20 )
			{
				strcat( path, "...  " );
				break;
			}
			strcat(path,hl->data);
			strcat(path," ");
			hl=hl_findnextheader(hl);
		}
		if(path[0])
		{
			path[strlen(path)-1]=0;
			addd(&tlist,2,"Status............: %s",path);
		}
	
		hl=hl_findheader(hlist,"BET");
		if(hl) addd(&tlist,2,"Betreff...........: %s",hl->data);

		hl=hl_findheader( hlist, "ZUSAMMENFASSUNG" );
		if(hl) addd(&tlist,2,"Kommentar.........: %s",hl->data);
		
		hl=hl_findheader( hlist, "LEN" );
		if(hl) addd(&tlist,2,"Länge.............: %s Bytes",hl->data);

		hl=hl_findheader( hlist, "EDA" );
		if(hl) {
			p=hl->data;
			addd(&tlist,2,"Datum.............: %.2s.%.2s.%.4s %.2s:%.2s:%.2s (%s)",
				&p[6],&p[4],p,
				&p[8],&p[10],&p[12],
				&p[14]);
		}
	}	
	hl=hl_findheader( hlist, "BEZ" );
	if(hl) {
		getmailinfo(hl->data,path);
		if(path[0]) addd(&tlist,2,"Bezugsnachricht...: %s",path);
	}

	rt= m->m.incomtime - m->m.time;

	if( rt > ( 3600 * 24 ) )
	{
		addd(&tlist,2,"Laufzeit..........: %ld Tag%s, %ld Stunde%s, %ld Minute%s, %ld Sekunde%s",
			rt / ( 3600 * 24 ), ( rt / ( 3600 * 24 ) == 1 ) ? "" : "e",
			( rt/3600 ) % 24 ,(((rt/3600)%24)==1)?"":"n",
			(rt/60)%60,((rt/60)%60)==1?"":"n",
			rt%60,(rt%60)==1?"":"n");
	}
	else
	{
		addd(&tlist,2,"Laufzeit..........: %ld Stunde%s, %ld Minute%s, %ld Sekunde%s",
			rt/3600,((rt/3600)==1)?"":"n",
			(rt/60)%60,((rt/60)%60)==1?"":"n",
			rt%60,(rt%60)==1?"":"n");
	}
	hl_freeheader( hlist );
	addd(&tlist,2,"Flags.............: %s%s%s%s%s%s%s%s%s%s%s",
		(m->m.flags&MMF_GOTEB)?"!EMPFANG BESTÄTIGT! ":"",
		(m->m.flags&MMF_READ)?"GELESEN ":"",
		(m->m.flags&MMF_ARCHIVE)?"HALTEN ":"",
		(m->m.flags&MMF_DEL)?"LÖSCHEN ":"",
		(m->m.flags&MMF_UNSEEN)?"NEU ":"",
		(m->m.flags&MMF_OUT)?"AUSGEHEND ":"",
		(m->m.flags&MMF_SHOW)?"WIEDERVORLAGE ":"",
		(m->m.flags&MMF_MDCRYPT)?"MDCRYPT ":"",
		(m->m.flags&MMF_PGPCRYPT)?"PGP-CRYPT ":"",
		(m->m.flags&MMF_PGPSIGNED)?"PGP-SIGNIERT ":"",
		(m->m.flags&MMF_FOLD)?"GEFALTET":""
	);

	if( msg->pix.commentsize )
	{
		int style = ! ( prefs.flags & MDF_NOREADERSTYLES );
		int quote = TRUE;

		msg_initread( msg, MC_COMMENT );
		addd( &tlist, 0, "" );
		addd( &tlist, 2, "Kommentar:" );
		addd( &tlist, 0, "" );
		while( msg_read( msg, path, 512 ) )
		{
			if( style )
			{
				if( path[ 0 ] == '-' && path[ 1 ] == '-' )
				{
					if( !*stpblk( &path[ 2 ] ) )
					{
						quote = 0;
						style = 0;
					}
				}
			}
			addqt( &tlist, style, quote, path );
		}
		msg_endread( msg );
		addd( &tlist, 0, "" );
		addd( &tlist, 2, "Nachrichteninhalt:" );
		addd( &tlist, 0, "" );
	}
	else
		addd( &tlist, 0, "" );

	if( m->m.flags & MMF_BIN )
	{
		addd( &tlist, 0, "Binärnachricht. Auslagern mit 'x'");

		path[ 0 ] = 0;

		if( DataTypesBase )
		{
			BPTR lock;
			struct DataType *dt;
			struct DataTypeHeader *dth;
		    STRPTR tdesc;
		    STRPTR gdesc;
		    ULONG ttype;

			strcpy( path, prefs.datadir );
			addpart( path, "__mddt.temp" );
			msg_copy( msg, path, MC_DATA );

			lock = Lock( path, SHARED_LOCK );
			if( lock )
			{
				dt = ObtainDataType( DTST_FILE, ( APTR ) lock, TAG_DONE );
				if( dt )
				{
					dth = dt->dtn_Header;

				    /* Get the coarse type */
				    ttype = dth->dth_Flags & DTF_TYPE_MASK;

				    /* Get a pointer to the text strings */
				    tdesc = GetDTString (ttype + DTMSG_TYPE_OFFSET);
				    gdesc = GetDTString (dth->dth_GroupID);

					addd( &tlist, 0, "" );

					addd( &tlist, 0, "DataTypes-Analyse:" );

					addd( &tlist, 0, "   Beschreibung..: %s", dth->dth_Name );
				    addd( &tlist, 0, "   Base Name.....: %s", dth->dth_BaseName);
				    addd( &tlist, 0, "   Typ...........: %ld - %s", ttype, tdesc);
				    addd( &tlist, 0, "   Gruppe........: %s", gdesc);
				    addd( &tlist, 0, "   ID............: %4.4s", &dth->dth_ID );

					if( ttype == 1 )
						redoasc = TRUE;

					ReleaseDataType( dt );
				}
				UnLock( lock );
			}
		}
		if( WhatIsBase )
		{
			BPTR lock;

			if( !path[ 0 ] )
			{
				strcpy( path, prefs.datadir );
				addpart( path, "__mddt.temp" );
				msg_copy( msg, path, MC_DATA );
			}

			lock = Lock( path, SHARED_LOCK );
			if( lock )
			{
				p = GetIDString( WhatIsTags( path, WI_Deep, DEEPTYPE, TAG_DONE ) );

				addd( &tlist, 0, "" );
				addd( &tlist, 0, "WhatIs-Analyse...: %s", p );

				if( !strcmp( p, "Text" ) )
					redoasc = TRUE;

				UnLock( lock );
			}
		}
		if( path[ 0 ] )
			DeleteFile( path );
	}
	if( ! ( m->m.flags & MMF_BIN ) || redoasc )
	{
		int style = ! ( prefs.flags & MDF_NOREADERSTYLES );
		int quote = TRUE;

		if( redoasc )
		{
			addd( &tlist, 0, "" );
			addd( &tlist, 2, "Nachrichteninhalt in Textform:" );
			addd( &tlist, 0, "" );
		}

		msg_initread( msg, MC_DATA );
		while( msg_read( msg, path, 512 ) )
		{
			if( style )
			{
				if( path[ 0 ] == '-' && path[ 1 ] == '-' )
				{
					if( !*stpblk( &path[ 2 ] ) )
					{
						style = 0;
						quote = 0;
					}
				}
			}
			addqt( &tlist, style, quote, path );
		}
		msg_endread( msg );
	}

	msg_close( msg );

	setupscroller( &tlist, 2 );
	if( redotop > 0 )
	{
		setscrollerstate( redotop );
		redotop = 0;
	}
	else
		displayscroller();

	if( mmcount )
	{
		struct vmail *vm=(struct vmail*)mlist.lh_Head;
		int count = 0;

		while( vm->n.mln_Succ )
		{
			if( vm->sel )
				count++;

			if( vm == n )
				break;

			vm = ( struct vmail * ) vm->n.mln_Succ;
		}
		preport( 0, 1, "NACHRICHT LESEN: Brett %s (%lD. von %lD markierten)", cmb->b.name, count, mmcount );
	}
	else
	{
		preport( 0, 1, "NACHRICHT LESEN: Brett %s",cmb->b.name);
	}

	if( !strncmp( m->m.absender, "an ", 3 ) )
		preport(1,1,"\"%s\" %s",m->m.betreff,m->m.absenderreal[0]?m->m.absenderreal:m->m.absender);
	else
		preport(1,1,"\"%s\" von %s",m->m.betreff,m->m.absenderreal[0]?m->m.absenderreal:m->m.absender);

	dorexx( 2 );

	ClearPointer( w );
	wsig = 1 << w->UserPort->mp_SigBit;
	while(!Done)
	{
		while(!(mp=(struct IntuiMessage*)GetMsg(w->UserPort))) 
		{
			sigs = Wait( wsig | rexxsig );
			if( rexxsig && ( sigs & rexxsig ) )
				dorexx( 2 );
		}
		im=*mp;
		ReplyMsg(mp);

		switch(im.Class)
		{
			case IDCMP_REFRESHWINDOW:
				BeginRefresh( w );
				displayscroller();
				EndRefresh( w, TRUE );
				break;

			case IDCMP_CLOSEWINDOW:
				doaskquit();
				break;

			case IDCMP_NEWSIZE:
				scrollerresize();
				break;

			case MOUSEBUTTONS:
				if( scrollerdoclick( &im ) == -1 )
					Done = 1;
				break;
			case MOUSEMOVE: scrollerdomove(&im); break;
			case GADGETDOWN: scrollerdogad(&im); break;
			case GADGETUP:
				rc = scrollerdogad( &im );
				if( !rc )
					break;
				im.Class	= RAWKEY;
				im.Code 	= rc & 0xff;
				im.Qualifier = (rc & 0x100) ? QSHIFT : 0;
				goto rawkey;
			case MENUPICK:
						rc=procmenu(im.Code,im.Qualifier);
						calcmcount();
				        if(rc<0)
						{
							if( oldflags != ( prefs.flags & ( MDF_SHOWALL | MDF_GADGETS | MDF_NOREADERSTYLES ) ) )
							{
								redotop = getscrollerstate();
								redo=1;
								Done=1;
							}
							break;
						}
						
				       im.Code=rc&0xff;
				       im.Qualifier=(rc&0x100)?IEQUALIFIER_LSHIFT:0;
					/* fallthrough */
rawkey:
			case RAWKEY: if(scrollerdokey(&im)) switch(im.Code) {
					case 0x0d:
						if( im.Qualifier & IEQUALIFIER_RSHIFT )
						{
							domailinfo( n );
						}
						break;

					case 0x50:
					case 0x51:
					case 0x52:
					case 0x53:
					case 0x54:
						dorexxcmd( 0, im.Code - 0x50 + ( ISSHIFT( &im ) ? 5 : 0 ) );
						break;

					case 0x55:
					case 0x56:
					case 0x57:
					case 0x58:
					case 0x59:
						dorexxcmd( 2, im.Code - 0x55 + ( ISSHIFT( &im ) ? 5 : 0 ) );
						break;

					case 0x27:  if( ISSHIFT( &im ) )
								{
									if( askreq( "Thread wirklich killen?\nDie Nachrichten und alle Antworten darauf werden\ngelöscht und können nicht mehr restauriert werden!", "Killen|Abbruch" ) )
									{
										dokillthread( n->m, 0, 0 );
										removekilled( mix );
										ClearPointer( w );
										wrotenewmails = TRUE;
										Done = 1;
									}
								}
								else
									docopymail( n );
								break;

					case 0x16: if( ISSHIFT( &im ) )
									dokilluser( n );
								else
									doextractmailuudecode( n );
								break;

					case 0x5f: showguidegads(&im, "nachrichtenlesen"); break;

					case 0x40: im.Code=0x4d; im.Qualifier=IEQUALIFIER_LSHIFT; scrollerdokey(&im); break;

					case 0x43:
					case 0x44: im.Code=0x4d; scrollerdokey(&im); break;

					case 0x5d:
					case 0x0f: 
					case 0x45: if( ISSHIFT( &im ) )
								Done = 2;
							   else
								Done = 1;
							   break;
								
					/* Mailfunktionen */

					case 0x34:	lockwindow();
								doviewmail( n );
								unlockwindow();
								break;

					case 0x32:  lockwindow();
								doextractmail( n, ISSHIFT( &im ) );
								unlockwindow();
								break;

					case 0x22:  lockwindow();
								doprintmail( n );
								unlockwindow();
								break;

					case 0x11:	
								lockwindow();
								if( ISSHIFT( &im ) )
								{
									resendmail( n );
								}
								else
								{
									if(doweitermail(n))
										wrotenewmails = cmb->newmails;
								}
								unlockwindow();
								break;

					case 0x21:	if(ISSHIFT(&im)) dosaveuser(n);
								else
								{
									lockwindow();
									doarcmail(n);
									preport(1,1,"Nachricht archiviert.");
									unlockwindow();
								}
								break;

					case 0x20:	lockwindow();
								if(doanswermail(n,1,ISSHIFT(&im)))
									wrotenewmails = cmb->newmails;
								unlockwindow();
								break;

					case 0x19:	lockwindow();
								if(doanswermail(n,0,ISSHIFT(&im)))
									wrotenewmails = cmb->newmails;
								unlockwindow();
								break;

					case 0x04:	lockwindow();
								checksignature( n );
								unlockwindow();
								break;

					case 0x5b:
					case 0x24:	n->m->m.flags^=MMF_READ;
								Done=redo=1;
								mix->changed = 1;
								donttouchflags = TRUE;
								break;

					case 0x5a:
					case 0x25:	n->m->m.flags^=MMF_ARCHIVE;
								mix->changed = 1;
								Done=redo=1; break;

					case 0x4a:
					case 0x46:	n->m->m.flags^=MMF_DEL;
								if( ( n->m->m.flags & MMF_DEL ) && ( prefs.flags2 & MDF2_HARDDEL ) )
									n->m->m.flags &= ~MMF_ARCHIVE;	
								mix->changed = 1;
								Done=redo=1; break;

					case 0x5c:	im.Qualifier |= QSHIFT;	// Simulate Shift
					case 0x01:	if(ISSHIFT(&im))
								{
									mix->changed = 1;
									n->m->m.flags |= MMF_SHOW;
									Done=redo=1;
									donttouchflags = TRUE;
								}
								break;

					case 0x5e:
					case 0x36:	tmv = fnvm( n );
								if( tmv )
								{
									n = tmv;
									Done = redo = 1;
								}
								else
								{
									if( prefs.flags2 & MDF2_NEXTNEWBOARD )
									{
										if( prefs.flags2 & MDF2_NEXTNEWBOARDASK )
										{
											char *p = findnextboardwithnewmails( cmb );

											if( !p )
											{
												askreq( "Keine weiteren neuen Nachrichten\nin diesem Brett.\n\nKeine weiteren Bretter mit neuen Nachrichten.", "Ok" );
												break;
											}
											if( !askreq( "Keine weiteren neuen Nachrichten\nin diesem Brett. Wollen Sie in das\nnächste Brett mit neuen Nachrichten:\n%s\nspringen?",
												"Weiterspringen|Stopp", p
											))
											break;
										}
										donextnewboard = 2;
										Done = TRUE;
									}
									else displaybeep();
								}
								break;

					case 0x42:	/* TAB naechste ungelesene */
								tmv=findnextunread(n); if(tmv) { n=tmv; Done=redo=1; }
								break;

					case 0x2d:
					case 0x2f:
					case 0x4e:
					case 0x4f:	tmv=findfup2(&im,n);
							if(tmv) { n=tmv; Done=redo=1; }
							break;

				     }
				     break;

			case IDCMP_MENUHELP: domenuhelp("brett",&im); break;
		}
		
	}

xit:
	freedlist();	
	if( redo )
		goto redo;

	if( scs )
	{
		if( !mmcount && !donextnewboard )
			popscs( scs );
		else
			popscsnv( scs );
	}

	OnMenu(w,SHIFTMENU(0)|SHIFTITEM(NOITEM));
	OnMenu(w,SHIFTMENU(2)|SHIFTITEM(0));
	OnMenu(w,SHIFTMENU(4)|SHIFTITEM(NOITEM));
	for(rc=0; rc<12; rc++)
		OnMenu(w,SHIFTMENU(3)|SHIFTITEM(rc));
	OnMenu(w,SHIFTMENU(5)|SHIFTITEM(NOITEM));
	if( pgpavail )
		OnMenu(w,SHIFTMENU(6)|SHIFTITEM(NOITEM));

	return( Done == 2 );
}

static void readmails(void)
{
	struct vmail *n=(struct vmail*)mlist.lh_Head;
	APTR scs;

	rtSetWaitPointer(w);
	wrotenewmails = FALSE;

	if(!mmcount)
	{
		n=(struct vmail*)GetEntry(&mlist,getscrollercurrent());
		readmail(n);
		return;
	}

	scs = pushscs();
	savesel();
	while(n->n.mln_Succ)
	{
		if( n->sel )
		{
			if( readmail( n ) )
				break;
		}
		n=(struct vmail*)n->n.mln_Succ;
	}
	n=(struct vmail*)mlist.lh_Head;
	while(n->n.mln_Succ)
	{
		n->sel = 0;
		n=(struct vmail*)n->n.mln_Succ;
	}
	n->sel=0;
	popscs( scs );
}

#define EM_OK 1
#define EM_CANCEL 2
#define EM_EDIT 3
#define EM_EDITCOMMENT 4
#define EM_EDITHEADER 5
#define EM_INFO 6
#define EM_PARK 7

static struct mmail *findmailbymidpid( struct mindex *mix, ULONG mID, ULONG pID )
{
	struct mmail * mm = ( struct mmail * ) mix->maillist.lh_Head;

	while( mm->n.mln_Succ )
	{
		if( mm->m.pufferID == pID && mm->m.mailID == mID )
			return( mm );
		mm = ( struct mmail * ) mm->n.mln_Succ;
	}
	return( NULL );
}

static int doeditmail( struct vmail *n )
{
	struct msghandle *msg;
	struct hlist *hlist;
	int Done = FALSE;
	struct ogwin *ogw;
	struct IntuiMessage *im;
	struct Window *w;
	ULONG mID, pID;
	char buffer[ 128 ];
	int c, d;
	struct mindex *spoolmix;
	struct mbrett *spool = findbrett( "/»SPOOL", 0 );

	/*if(n->m->m.flags&MMF_BIN) { displaybeep(); return(0); }*/

	msg = msg_openv( n );
	if( !msg )
		return( 0 );

	DeleteFile( TMPCOMMENTNAME );
	DeleteFile( TMPEDITNAME );

	msg_copy( msg, TMPEDITNAME, MC_DATA );
	msg_copy( msg, TMPCOMMENTNAME, MC_COMMENT );
	hlist = msg_loadheader( msg );

	mID = n->m->m.mailID;
	pID = n->m->m.pufferID;

	msg_close( msg );

	ogw = ogreInitWindow( scr, 0, 0, "Nachricht editieren" );
	ogreAddGroup( ogw, 0, OGFRAME_NONE, NULL );
	ogreAddText( ogw, 0, "Info:", EM_INFO, "", 46, TRUE );
	ogreAddButton( ogw, 1, 'e', "Text _editieren", EM_EDIT );
	ogreAddButton( ogw, 1, 'k', "_Kommentar editieren", EM_EDITCOMMENT );
	ogreAddButton( ogw, 1, 'h', "_Header editieren", EM_EDITHEADER );
	ogreAddButton( ogw, 2 | OGB_ONENTER, 'v', "_Verschicken", EM_OK );
	ogreAddButton( ogw, 2 , 'p', "_Parken", EM_PARK );
	ogreAddHelp( ogw, 2 );
	ogreAddButton( ogw, 2 | OGB_ONESC, 'a', "_Abbruch", EM_CANCEL );
	w = ogreOpenWindow( ogw );

	if( !w )
	{
		return( 0 );
	}

	ogreEnable( ogw, !( n->m->m.flags & MMF_BIN ), EM_EDIT, 0 );

	while( !Done )
	{
		/* Infotext erzeugen */
		c = getfilelen( TMPCOMMENTNAME );
		d = getfilelen( TMPEDITNAME );
		buffer[ 0 ] = 0;
		if( d > 0 )
			sprintf( buffer, "%lD Byte Inhalt ", d );
		if( c > 0 )
		{
			if( buffer[ 0 ] )
				strcat( buffer, ", " );
			asprintf( buffer, "%lD Byte Kommentar", c );
		}
		ogreSetStringValue( ogw, EM_INFO, buffer );

		im = ogreWaitIM( ogw );

		if( im->Class == IDCMP_GADGETHELP)
			showguidenum( "editwin_gads", im->Code );
		else if( im->Class == GADGETUP )
			switch( im->Code )
			{
				case EM_OK:
					Done = 2;
					break;

				case EM_PARK:
					Done = 3;
					break;

				case EM_CANCEL:
					Done = 1;
					break;

				case EM_EDIT:
					calleditor( TMPEDITNAME );
					ActivateWindow( w );
					break;

				case EM_EDITCOMMENT:
					calleditor( TMPCOMMENTNAME );
					ActivateWindow( w );
					break;

				case EM_EDITHEADER:
					doeditheader( hlist, "Header editieren" );
					break;
			}
			ogreIMReply( ogw, im );

	}

	ogreExitWindow( ogw );

	/* Geänderte Nachricht abspeichern... */
	if( Done > 1 )
	{
		msg_replace( TMPCOMMENTNAME, -1, TMPEDITNAME, -1,
			pID, mID, hlist
		);

		/* Mail-Struktur updaten */
		header2mail( hlist, &n->m->m );

		n->m->m.maillen = getfilelen( TMPEDITNAME );

		// Im Spoolbrett updaten?
		if( spool != cmb )
		{
			struct mmail *mm;
			spoolmix = loadbrettixquiet( spool );

			if( spoolmix )
			{
				mm = findmailbymidpid( spoolmix, mID, pID );

				if( mm )
				{
					ULONG oldflags;

					oldflags = mm->m.flags;
					mm->m = n->m->m;
					mm->m.flags = oldflags;
					spoolmix->changed = 1;

					if( Done == 2 )
						mm->m.flags &= ~MMF_ARCHIVE;
					else
						mm->m.flags |= MMF_ARCHIVE;
				}
				savebrettix( spoolmix, spool );
				freebrettix( spoolmix );
			}		
			if( cmb->b.name[ 0 ] == '/' && !hl_findheader( hlist, "ABS" ) )
			{
				sprintf( n->m->m.absender, "%s@%s%s", prefs.username, prefs.boxname, prefs.boxdomain ); 
				strcpy( n->m->m.absenderreal, prefs.userrealname );
			}
		}
		else
		{
			//struct header *hl = hl_findheader( hlist, "ABS" );
			struct header *hl2 = hl_findheader( hlist, "EMP" );
			/* Im Spoolbrett editiert; wir müssen EMP:s absuchen */

			if( Done == 2 )
				n->m->m.flags &= ~MMF_ARCHIVE;
			else
				n->m->m.flags |= MMF_ARCHIVE;

			while( hl2 )
			{
				struct mbrett *mb;

				if( hl2->data[ 0 ] == '/' )
					mb = findbrett( hl2->data, 0 );
				else
					mb = findpmbrett( hlist );

				if( mb )
				{
					struct mindex *mix = loadbrettixquiet( mb );

					if( mix )
					{
						struct mmail *mm = findmailbymidpid( mix, mID, pID );

						if( mm )
						{
							ULONG oldflags;

							oldflags = mm->m.flags;
							mm->m = n->m->m;
							mm->m.flags = oldflags;
							if( hl2->data[ 0 ] == '/' )
							{
								sprintf( mm->m.absender, "%s@%s%s", prefs.username, prefs.boxname, prefs.boxdomain ); 
								strcpy( mm->m.absenderreal, prefs.userrealname );
							}
							mix->changed = 1;
						}
						savebrettix( mix, mb );
						freebrettix( mix );
					}
				}
				hl2 = hl_findnextheader( hl2 );
			}

			n->m->m.absenderreal[ 0 ] = 0;
		}
	}
	DeleteFile( TMPCOMMENTNAME );
	DeleteFile( TMPEDITNAME );
	return( -1 );
}

static int doeditmails(void)
{
	struct vmail *n=(struct vmail*)mlist.lh_Head;
	int rc=0;

	/*if(stricmp(cmb->b.name,"/»SPOOL")) return(0);*/

	rtSetWaitPointer(w);
	if(!mmcount) {
		n=(struct vmail*)GetEntry(&mlist,getscrollercurrent());
		if(n) rc|=doeditmail(n);
		if( rc )
		{
			mix->changed = 1;
			cmb->newmails = 1;
		}
		return(rc);
	}
	savesel();
	while(n->n.mln_Succ) {
		if(n->sel) {
			rc|=doeditmail(n);
			n->sel=0;
		}
		n=(struct vmail*)n->n.mln_Succ;
	}

	if( rc )
	{
		cmb->newmails = 1;
		mix->changed = 1;
	}
	return(rc);
}

static int findmailnumbymidcrc( ULONG cmpid )
{
	struct vmail *n=(struct vmail*)mlist.lh_Head;
	int count = 0;

	while( n->n.mln_Succ )
	{
		if( n->m->m.midcrc == cmpid )
			return( count );
		count++;
		n = ( struct vmail * ) n->n.mln_Succ;	
	}
	return( -1 );
}

extern int scrollerenter;

static int doinhalt1( struct mbrett *mbrett, int nextnew )
{
	struct IntuiMessage *mp,im;
	long rc;
	int Done=0;
	ULONG oldflags;
	struct AppMessage *am;
	ULONG sig;

	cmb=mbrett;

	preport(0,1,"Brett: %s",mbrett->b.name);
	preport(1,1,"Lade Brettindex...");

	mix=loadbrettix(mbrett);
	if(!mix)
		return(0);

	/* Menus umschalten */
	OffMenu(w,SHIFTMENU(1)|SHIFTITEM(NOITEM));

	OnMenu(w,SHIFTMENU(2)|SHIFTITEM(NOITEM));
	OnMenu(w,SHIFTMENU(3)|SHIFTITEM(NOITEM));

	if(stricmp(mbrett->b.name,"/»SPOOL"))
		OffMenu(w,SHIFTMENU(2)|SHIFTITEM(9));
	else
		OnMenu(w,SHIFTMENU(2)|SHIFTITEM(9));

	if(stricmp(mbrett->b.name,"/»ARCHIV"))
		OnMenu(w,SHIFTMENU(2)|SHIFTITEM(5));
	else
		OffMenu(w,SHIFTMENU(2)|SHIFTITEM(5));

	if(mbrett->b.name[0]!='/')
	{
		OffMenu(w,SHIFTMENU(2)|SHIFTITEM(3)|SHIFTSUB(2));
		OffMenu(w,SHIFTMENU(2)|SHIFTITEM(3)|SHIFTSUB(3));
	}
	else
	{
		OnMenu(w,SHIFTMENU(2)|SHIFTITEM(3)|SHIFTSUB(2));
		OnMenu(w,SHIFTMENU(2)|SHIFTITEM(3)|SHIFTSUB(3));
	}

	if( rexxsig )
	{
		OffMenu( w, FULLMENUNUM( 7, 3, NOSUB ) );
		OnMenu( w, FULLMENUNUM( 7, 4, NOSUB ) );
	}

	/*lastmailnum = -1;*/

redo:
	preport( 1, 1, "Sortiere Brettindex..." );
	oldflags = prefs.flags & ( MDF_SHOWREAL | MDF_SORTDATE | MDF_GADGETS | MDF_FILTERRE );
	makemlist( &mix->maillist, &mlist );
	wrotenewmails = 0;
	cmb->newmails = 0;

	if( nextnew )
	{
		struct vmail *vm = ( struct vmail * ) mlist.lh_Head;
		lastmailnum = 0;
		while( vm->n.mln_Succ )
		{
			if( ( vm->m->m.flags & ( MMF_UNSEEN | MMF_SHOW ) ) ||
			    ( ( vm->m->m.flags & MMF_FOLD ) && newinfold( vm->m->firstbez ) ) )
			{
				break;
			}
			vm = ( struct vmail * ) vm->n.mln_Succ;
			lastmailnum++;
		}
		nextnew--;
	}
	else if( newmailptr && ( oldbrettmaxnum != cmb->b.mails ) )
	{
		struct vmail *vm = (struct vmail *) mlist.lh_Head;

		lastmailnum = 0;
		while( vm->n.mln_Succ )
		{
			if( vm->m == newmailptr )
				break;
			vm = (struct vmail *) vm->n.mln_Succ;
			lastmailnum++;
		}
		newmailptr = NULL;
	}

	oldbrettmaxnum = cmb->b.mails;

	calcmcount();
	setupscroller( &mlist, 1 );
	setscrollerstate( inhaltscstate );
	if( usecmpid )
	{
		usecmpid = FALSE;
		lastmailnum = findmailnumbymidcrc( cmpid );
	}

	if( lastmailnum >= 0 )
	{
		setscrollercurrent( lastmailnum );
		normalizescroller();
		updateprop();
		lastmailnum = -1;
	}
	displayscroller();

	dorexx( 1 );

	ClearPointer(w);

	if( nextnew )
	{
		nextnew = 0;
		readmails();
		dorexx( 1 );
		if( donextnewboard )
		{
			freeinhalt();
			return( 0 );
		}
		if( wrotenewmails)
		{
			wrotenewmails = FALSE;
			usecmpid = TRUE;
			freeinhalt();
			return(-1);
		}
		setscrollercurrent( lastmailnum );
		showcurrentitem();
	}

	while( !Done )
	{
		if( scrollerenter )
		{
			scrollerenter = FALSE;
			goto readmailslabel;
		}

		if(!(mp=(struct IntuiMessage*)GetMsg(w->UserPort)))
		{
			sig = Wait( rexxsig | appwindowsig | ( 1 << w->UserPort->mp_SigBit ) );

			if( sig & appwindowsig )
			{
				while( ( am = ( struct AppMessage *) GetMsg( appwindowmp ) ) )
				{
					if( am->am_NumArgs )
					{
						char name[ 256 ];
						struct WBArg *wba = am->am_ArgList;

						NameFromLock( wba->wa_Lock, name, 255 );
						AddPart( name, wba->wa_Name, 255 );
					
						lockwindow();
						rc = donewmail( name, cmb, NULL );
						unlockwindow();
						if( rc )
						{
							ReplyMsg( am );
							freeinhalt();
							inhaltscstate = getscrollerstate();
							wrotenewmails = cmb->newmails;
							if( wrotenewmails )
								return( -1 );
						}
							
					}
					ReplyMsg( am );
				}
			}

			if( rexxsig && ( sig & rexxsig ) )
				dorexx( 1 );

			continue;
		}
		im=*mp;
		ReplyMsg(mp);

		switch(im.Class)
		{
			case IDCMP_REFRESHWINDOW:
				BeginRefresh( w );
				displayscroller();
				EndRefresh( w, TRUE );
				break;

			case IDCMP_CLOSEWINDOW:
				doaskquit();
				break;

			case IDCMP_NEWSIZE:
				scrollerresize();
				break;

			case MOUSEBUTTONS:
				rc=scrollerdoclick(&im);
				if( rc > 0 )
				{
readmailslabel:
					readmails();
					dorexx( 1 );
					if( donextnewboard )
					{
						Done = TRUE;
						break;
					}
					if( wrotenewmails)
					{
						wrotenewmails = FALSE;
						usecmpid = TRUE;
						freeinhalt();
						return(-1);
					}
					setscrollercurrent( lastmailnum );
					showcurrentitem();
				}
				else if( rc == -1 )
				{
					Done = 1;
					break;
				}
				else if( rc == -2 )
				{
					im.Class	= RAWKEY;
					im.Code 	= 0x36;
					im.Qualifier 	= 0;
					goto rawkey;
				}
			 	calcmcount(); break;
			case MOUSEMOVE: scrollerdomove(&im); break;
			case GADGETDOWN: scrollerdogad(&im); break;
			case GADGETUP:
				rc = scrollerdogad( &im );
				if( !rc )
					break;
				else if( rc == 0x200 )
				{
					if( prefs.flags2 & MDF2_ESCCLRNEW )
						im.Qualifier = 0;
					else
						im.Qualifier = QSHIFT;

					Done = 1;
					break;
				}
				else if( rc == 0x201 )
				{
					if( prefs.flags2 & MDF2_ESCCLRNEW )
						im.Qualifier = QSHIFT;
					else
						im.Qualifier = 0;

					Done = 1;
					break;
				}

				im.Class	= RAWKEY;
				im.Code 	= rc & 0xff;
				im.Qualifier = (rc & 0x100) ? QSHIFT : 0;
				goto rawkey;
			case MENUPICK: rc=procmenu(im.Code,im.Qualifier);
				    if(rc<0)
					{
						if( didsortin )
						{
							/* Falls Spoolbrett, löschen */
							if( !strcmp( cmb->b.name, "/»SPOOL" ) )
								mix->changed = 0;
							freeinhalt();
							return( 0 );
						}
						if((prefs.flags&(MDF_SHOWREAL|MDF_SORTDATE|MDF_GADGETS|MDF_FILTERRE))!=oldflags)
						{
							inhaltscstate=getscrollerstate();
							freemlist();
							goto redo;
						}
						calcmcount();
						break;
					}
					if( wrotenewmails )
					{
						freeinhalt();
						unlockwindow();
						return( -1 );
					}
				    im.Code=rc&0xff;
				    im.Qualifier=(rc&0x100)?IEQUALIFIER_LSHIFT:0;
					/* fallthrough */
rawkey:
			case RAWKEY: 
					rc = scrollerdokey( &im );
					if( rc == 1 )
						calcmcount();
					else if( rc ) switch(im.Code) {

					case 0x0d:
						if( im.Qualifier & IEQUALIFIER_RSHIFT )
						{
							domailinfo( getcurrentmail() );
						}
						break;

					case 0x50:
					case 0x51:
					case 0x52:
					case 0x53:
					case 0x54:
						dorexxcmd( 0, im.Code - 0x50 + ( ISSHIFT( &im ) ? 5 : 0 ) );
						break;

					case 0x55:
					case 0x56:
					case 0x57:
					case 0x58:
					case 0x59:
						dorexxcmd( 2, im.Code - 0x55 + ( ISSHIFT( &im ) ? 5 : 0 ) );
						break;


					case 0x16: if( ISSHIFT( &im ) )
									dokilluser( getcurrentmail () );
								else
								{
									lockwindow();
									iteratemsglist( doextractmailuudecode );
									displayscroller();
									unlockwindow();
								}
								break;
					case 0x2d:
					case 0x2f:
					case 0x4e:
					case 0x4f: findfup(&im); break;

					case 0x21: if(ISSHIFT(&im)) dosaveusers(); else { xscroller(); doarcmsg(); incscroller(); displayscroller(); } break;

					case 0x5c: im.Qualifier |= QSHIFT;

					case 0x1: if(ISSHIFT(&im)) { dosetnewmsg(); } break;

					case 0x32: xscroller(); doextractmsg(ISSHIFT(&im)); incscroller(); displayscroller(); break;

					case 0x34: xscroller(); doviewmsg(); displayscroller(); incscroller(); break;

					case 0x22: xscroller(); doprintmsg(); displayscroller(); incscroller(); break;

					case 0x04: xscroller(); lockwindow(); checksignatures(); unlockwindow(); displayscroller(); incscroller(); break;

					case 0x5a:
					case 0x25: doholdmsg(ISSHIFT(&im)); break;

					case 0x5b:
					case 0x24: dosetreadmsg(ISSHIFT(&im)); break;

					case 0x28: dosetreadsel(); break;

					case 0x3c: im.Qualifier |= QSHIFT;
					case 0x2e: /* NUM-5 */
					case 0x23: /* Mail falten */
						inhaltscstate=getscrollerstate();
						lastmailnum = getscrollercurrent();
						dofold( ISSHIFT( &im ) ? 3 : 0);
						freemlist();
						goto redo;
					case 0x14: inhaltscstate=getscrollerstate(); dofold(ISSHIFT(&im)?2:1); freemlist(); lastmailnum = 0; goto redo;

					case 0x20: lockwindow(); inhaltscstate=getscrollerstate(); if(doanswer(1,ISSHIFT(&im)) && cmb->newmails ) { freeinhalt(); unlockwindow(); wrotenewmails = TRUE; return(-1); } unlockwindow(); break;
					case 0x19: lockwindow(); inhaltscstate=getscrollerstate(); if(doanswer(0,ISSHIFT(&im)) && cmb->newmails ) { freeinhalt(); unlockwindow(); wrotenewmails = TRUE; return(-1); } unlockwindow(); break;

					case 0x27:
						if( ISSHIFT( &im ) )
						{	
							inhaltscstate = getscrollerstate();
							
							if( killthread() )
							{
								if( getscrollercurrent() )
									inhaltscstate = ( inhaltscstate & 0xffff0000 ) + ( ( inhaltscstate & 0xffff ) - 1 );

								freemlist();
								makerlinks( mix );
								goto redo;
							}
						}
						else
							docopymails();
						break;

					case 0x43:
					case 0x44:
						readmails(); 
						dorexx( 1 );
						if( donextnewboard )
						{
							Done = TRUE;
							break;
						}
						if( wrotenewmails )
						{
							wrotenewmails = FALSE;
							usecmpid = TRUE;
							freeinhalt();
							return( -1 );
						}
						setscrollercurrent( lastmailnum );
						showcurrentitem();
						break;

					case 0x0f:
					case 0x5d:
					case 0x45: Done=1; break;

					case 0x5e:
					case 0x36:
								 /*n naechste neue, oder N alle neuen markieren */
								 domarknew(ISSHIFT(&im));

								 if( donextnewboard )
									Done = TRUE;

								 break;

					case 0x42: /* TAB naechste ungelesene */
								 domarknextunread(); break;

					case 0x37: /*m = nach absender, M alle */
								domarkbyabsender(&im); displayscroller(); break;

					case 0x12: lockwindow();
						inhaltscstate=getscrollerstate();
						if( (ISSHIFT(&im) ? doeditmails() : donewmail( NULL, cmb, NULL )) && cmb->newmails )
						{
							freeinhalt();
							unlockwindow();
							wrotenewmails = TRUE;
							return(-1);
						}
						unlockwindow();
						break;

					case 0x17: /*i*/ doinvsel(); displayscroller(); break;

					case 0x4a:
					case 0x46: 
						if(ISSHIFT(&im))
							doundelmsg();
						else
							dodelmsg();
						break;

					case 0x5f: showguidegads(&im,"nachrichtenauswahl"); break;

					case 0x11:
						lockwindow();
						if( ISSHIFT( &im ) )
						{
							iteratemsglist( resendmail );
						}
						else
						{
							if( doweiter(&im) && cmb->newmails )
							{
								wrotenewmails = TRUE;
								freeinhalt();
								unlockwindow();
								return( -1 );
							}
						}
						displayscroller();
						unlockwindow();
						break;

					case 0x18:	// Markierungen wiederherstellen
							restoresel();
							displayscroller();
							break;

				     }
					 calcmcount();
				     break;

			case IDCMP_MENUHELP: domenuhelp("brett",&im); break;
		}

	}

	if( prefs.flags2 & MDF2_ESCCLRNEW )
	{
		if( ! ISSHIFT( &im ) )
			domarkseen();
	}
	else
	{
		if( ISSHIFT( &im ) )
			domarkseen();
	}

	freeinhalt();
	return(0);
}

void doinhalt( struct mbrett *m, int nextnew )
{
	inhaltscstate	= 0;
	lastmailnum 	= 0;
	oldbrettmaxnum	= 0;
	newmailptr		= 0;
	wrotenewmails 	= 0;

	didsortin = FALSE;

	while( doinhalt1( m, nextnew ) )
		nextnew = 0;
}
