#include "microdot.h"
#include <exec/execbase.h>
#include "md_rexx.h"
#include <devices/keyboard.h>
#include <constructor.h>
#include <proto/locale.h>

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


#define MDRS_NAME "MicroDot.resource"
#define MDRS_ID "MicroDot Rendevousz Resource"

__aligned struct ReqToolsBase *ReqToolsBase;
struct Library  *RexxSysBase;
struct Library *GadToolsBase;
struct Library *KeymapBase;
struct Library *WorkbenchBase;
struct Library *DataTypesBase;
struct Library *XpkBase;
struct Library *WhatIsBase;

extern struct TextFont mdmicroFont;
static struct TextAttr mdmicroTA={"mdmicro.font",8,0,0};

static void *fbbitmapmem;

void __asm (*sabd_func)(register __a1 struct RastPort*,register __d0 int,register __d1 int,register __d2 int,register __a6 struct GfxBase*);

static struct mdsysnode mymdsysnode;

__aligned char *pubscreenname;
char *sortinbuffer;
struct LocaleInfo localeinfo;

char *startupscriptname;

int noreq;

long __stack = 32768;

BPTR keyseglist;
#ifdef MDV20
long __oslibversion = 39;
#else
long __oslibversion = 37;
#endif

/* Keyboard-Resethandler */

static struct IOStdReq kbreq;
static struct Interrupt kbint;
static int kbactive, inreset, resethandlerenabled;

struct MsgPort *multiport;

LONG brettlist_namesize;

#ifndef MDV20
USHORT isv39;
ULONG memf_no_expunge;
#endif

__aligned struct Interrupt memhandler;

int allow_trace, allow_rfc = TRUE;
ULONG screenlines, screencols, screenxsize, fontysize = 8, fontxsize = 8, gyoffs, fontbaseline = 6, topoffs;
int topborderoffs;
#include "rev.h"
#ifdef MDV20
char version[] = { "$VER: MicroDot020 " MDVER " " REVDATE };
#else
char version[] = { "$VER: MicroDot " MDVER " " REVDATE };
#endif
__aligned struct mdprefs prefs;
__aligned struct Window *w;
struct Screen *scr;
struct RastPort *rp;
struct Library *LocaleBase;
struct TextAttr top80 = { "topaz.font", 8, 0, 0 };	/* Requester only */
struct TextAttr realfontta; /* Rest */
struct TextAttr realfontta_bold; /* Rest */
struct TextFont *listfont;
struct TextAttr screenfontta;
static struct TextAttr menufontta;
static struct TextAttr menufontta_bold={0,0,FSF_BOLD,0};
static  struct NewScreen ns={0,0,640,256,2, 2,1, HIRES, CUSTOMSCREEN,&screenfontta,NULL,NULL,NULL};
static __aligned struct Image propimage;
static __aligned struct RDArgs *rda;
__aligned struct MsgPort *appwindowmp;
ULONG appwindowsig;
static struct AppWindow *appwindow;
UWORD screenpens[ 12 ];
static BOOL resetcurrentinput, resetcurrentoutput;
BOOL do_autoreorg, do_autocrunch;
int gadgetlistcount;

struct Gadget Pfeil1Gadg = {
	NULL,		/* NextGadget */
	640-16, 0,		/* LeftEdge, TopEdge */
	16, 9,		/* Width, Height */
	GADGHIMAGE,	/* Flags */
	RELVERIFY | GADGIMMEDIATE,	/* Activation */
	BOOLGADGET,	/* GadgetType */
	NULL,	/* GadgetRender */
	NULL,
	NULL,		/* GadgetText */
	0L,		/* MutualExclude */
	NULL,		/* SpecialInfo */
	3,		/* GadgetID */
	NULL,		/* UserData */
};

struct Gadget Pfeil2Gadg = {
	&Pfeil1Gadg,		/* NextGadget */
	640-16, 0,		/* LeftEdge, TopEdge */
	16, 9,		/* Width, Height */
	GADGHIMAGE,	/* Flags */
	RELVERIFY|GADGIMMEDIATE,	/* Activation */
	BOOLGADGET,	/* GadgetType */
	NULL,
	NULL,
	NULL,		/* GadgetText */
	0L,		/* MutualExclude */
	NULL,		/* SpecialInfo */
	2,		/* GadgetID */
	NULL,		/* UserData */
};


struct PropInfo propinfo={AUTOKNOB|PROPNEWLOOK|FREEVERT|PROPBORDERLESS,0,0,0,MAXBODY};

static char  infotxt1[256], infotxt2[256];
static struct IntuiText infoitext2 = { 0,0, JAM2, 0,0, &realfontta_bold, infotxt2, NULL };
static struct IntuiText infoitext1 = { 0,0, JAM2, 0,0, &realfontta_bold, infotxt1, &infoitext2 };
static UWORD infovec[] = { 0,0, 0,0};
static struct Border infoborder2 = {0,0, 1,0,JAM1, 2, infovec, NULL };
static struct Border infoborder1 = {0,0, 2,0,JAM1, 2, infovec, &infoborder2 };
static struct Gadget infogadget={&Pfeil2Gadg, 0,0,1,1,  GFLG_GADGHNONE,0,GTYP_BOOLGADGET, &infoborder1,NULL,&infoitext1,NULL,NULL,8574,0};
struct Gadget scrollgad={&infogadget, 625,12+16+3,15-4,-1,  GFLG_GADGHCOMP,GACT_FOLLOWMOUSE|GACT_IMMEDIATE|GACT_RELVERIFY,GTYP_PROPGADGET, &propimage, NULL, NULL, NULL, &propinfo, 1 ,0 };
static struct Gadget bottomextendgadget = { NULL, 0, 0, 0, 0,
 GFLG_GADGHNONE | GFLG_RELBOTTOM | GFLG_RELWIDTH,
 GACT_BOTTOMBORDER,
 GTYP_BOOLGADGET | GTYP_GZZGADGET,
 NULL, NULL, NULL, 0, NULL, 760
};

struct TagItem menuhelpti[] = {
	WA_MenuHelp, 	TRUE,
	WA_NewLookMenus,TRUE,
	WA_AutoAdjust, 	TRUE,
	WA_BusyPointer, TRUE,
	WA_RptQueue,	2,
	WA_MouseQueue,  2,
	TAG_DONE
};
static  struct ExtNewWindow nw2={
		0,0,0,0,
		2,1,
		IDCMP_REFRESHWINDOW | IDCMP_CLOSEWINDOW | IDCMP_MOUSEMOVE | IDCMP_GADGETUP | IDCMP_GADGETDOWN | IDCMP_RAWKEY | IDCMP_MENUPICK| IDCMP_INTUITICKS | IDCMP_MOUSEBUTTONS | IDCMP_MENUHELP | IDCMP_NEWSIZE,
		ACTIVATE | BACKDROP | BORDERLESS | WFLG_NW_EXTENDED,
		&scrollgad,
		NULL,
		NULL,
		NULL,
		NULL,
		300,80, (UWORD)~0,(UWORD)~0,
		CUSTOMSCREEN,
		menuhelpti
	};

char *currentprefsname = "microdot.prefs";

struct KeyMap conkeymap;

struct Device *ConsoleDevice;
static  struct IOStdReq confakereq;

char *progname; /* Filename of MicroDot */
#ifdef MDV20
static char prognamebuffer[ 128 ];
#endif

static struct Task *clocktask;

struct Menu *menustrip;
struct Menu *termmenustrip,*netcallmenustrip,*answermenustrip, *protomenustrip;
static void *menurkey;
void *miscmempool;

struct rtReqInfo *rinfo;
static APTR oldprwindowptr;

struct rtFileRequester *fr[7];

struct reginfo registerinfo;

static int startnetcall,startterminal, startnetcallmode;
static int resetgui;
int resolution11;
int netcall_resume;
int wbwindow;

static struct BitMap fontbrushBitMap;
static void *chipmempool;

#ifdef MDV20
#define WBSCREENTITLE "MicroDot020 V" MDVER " © 1993-99 Oliver Wagner, All Rights Reserved"
#else
#define WBSCREENTITLE "MicroDot V" MDVER " © 1993-99 Oliver Wagner, All Rights Reserved"
#endif

CONSTRUCTOR_P(initrnd,500)
{
	srand( time( NULL ) );
	return( 0 );
}


struct MsgPort *rexxport;
struct RexxHost *rexxhost;
ULONG rexxsig, rexxmode;

static struct List rexxl1, rexxl2, rexxl3;

struct rexxcmd {
	struct 	Node n;
	char 	name[ 20 ];	/* MenuName */
	char	file[ 32 ]; /* Script file name */
};

static void addrexxcmd( struct List *l, char *name )
{
	char path[ 128 ];
	struct DiskObject *dobj;
	struct rexxcmd *new;
	char *p;

	if( GetNumEntries( l ) > 31 )
		return;

	sprintf( path, "Rexx/%s", name );
	dobj = GetDiskObjectNew( path );
	if( !dobj )
		return;
	new = LibAllocPooled( miscmempool, sizeof( *new ) );
	if( !new )
		return;

	strcpy( new->file, name );

	p = FindToolType( dobj->do_ToolTypes, "PRI" );
	if( !p )
		p = FindToolType( dobj->do_ToolTypes, "PRIORITY" );
	if( p )
		new->n.ln_Pri = atoi( p );

	p = FindToolType( dobj->do_ToolTypes, "NAME" );
	if( p )
	{
		strncpy( new->name, p, 19 );
	}
	else
	{
		strcpy( path, name );
		p = strchr( path, '.' );
		*p = 0;
		strncpy( new->name, path, 19 );
	}

	FreeDiskObject( dobj );

	Enqueue( l, new );
}


static void readrexxdir( void )
{
	struct FileInfoBlock *fib;
	BPTR dirlock;

	NewList( ( struct List * ) &rexxl1 );
	NewList( ( struct List * ) &rexxl2 );
	NewList( ( struct List * ) &rexxl3 );

	if( !isv37 )
		return;

	dirlock = Lock( "Rexx", SHARED_LOCK );
	if( !dirlock )
		return;

	fib = allocfib();
	Examine( dirlock, fib );

	/* Verzeichnis durchsuchen */
	while( ExNext( dirlock, fib ) )
	{
		/* Keine Dirs */
		if( fib->fib_DirEntryType > 0 )
			continue;
		if( astcsma( fib->fib_FileName, "#?.mdrexx" ) )
			addrexxcmd( &rexxl1, fib->fib_FileName );
		else if( astcsma( fib->fib_FileName, "#?.mdbrexx" ) )
			addrexxcmd( &rexxl2, fib->fib_FileName );
		else if( astcsma( fib->fib_FileName, "#?.mdmrexx" ) )
			addrexxcmd( &rexxl3, fib->fib_FileName );
	}
	UnLock( dirlock );
	freefib( fib );
}


static void setuparexx( void )
{
	if( isv37 && RexxSysBase )
	{
		rexxport = CreateMsgPort();
		rexxsig = 1L << rexxport->mp_SigBit;
		rexxhost = SetupARexxHost( NULL, rexxport, NULL, NULL );
	}
}

static void cleanuparexx( void )
{
	if( rexxhost )
		CloseDownARexxHost( rexxhost );
	if( rexxport )
		DeleteMsgPort( rexxport );
}

int rexxquitflag;
void dorexx( int mode )
{
	rexxmode = mode;
	if( rexxhost )
	{
		ARexxDispatch( rexxhost );
		if( rexxquitflag )
			exit( 0 );
	}
}

/* Rexx-Makro ausführen */
void dorexxcmd( int l, int num )
{
	struct List *lp;
	struct rexxcmd *rxc;
	char cmd[ 128 ];

	switch( l )
	{
		case 0: lp = &rexxl1;
				break;
		case 1: lp = &rexxl2;
				break;
		case 2: lp = &rexxl3;
				break;
		default:
				return;
	}

	rxc = ( struct rexxcmd * ) GetEntry( lp, num );
	if( !rxc )
		return;

	sprintf( cmd, "Rexx/%s", rxc->file );
	SendRexxCommand( rexxhost, cmd, NULL );
}

void execrexxargswait( char *cmd, char *args, int wait )
{
	char path[ 256 ];

	if( rexxhost )
	{
		BPTR l;
		struct Message *m;

		sprintf( path, "PROGDIR:Rexx/%s.mdArexx", cmd );
		l = Lock( path, SHARED_LOCK );
		if( l )
		{
			NameFromLock( l, path, 200 );
			UnLock( l );
		}
		else
			sprintf( path, "Rexx/%s.mdArexx", cmd );

		if( args )
		{
			strcat( path, " " );
			strcat( path, args );
		}
	
		m = SendRexxCommand( rexxhost, path, NULL );

		if( m && wait )
		{
			for(;;)
			{
				if( rexxhost )
					ARexxDispatch( rexxhost );
				Delay( 2 );
				if( m->mn_Node.ln_Type == NT_REPLYMSG )
					break;
			}
		}
	}
}

void execrexxargs( char *cmd, char *args )
{
	execrexxargswait( cmd, args, FALSE );
}

void execrexx( char *cmd )
{
	execrexxargswait( cmd, NULL, FALSE );
}

void dorexxshell( void )
{
	BPTR f = openconsole( "MicroDOT-Rexx-Shell - HELP <Kommando> für HILFE" );
	BPTR oldin, oldout;

	oldin = SelectInput( f );
	oldout = SelectOutput( f );

	CommandShell( rexxhost, f, f, "MDREXX> " );

	SelectInput( oldin );
	SelectOutput( oldout );

	Close( f );
}

#define chdir mychdir
static void chdir( char *dir )
{
	BPTR lock = Lock( dir, SHARED_LOCK );
	if( lock )
		UnLock( CurrentDir( lock ) );
}

/* Keyboard Reset Handler */

static void remkbresethandler( void )
{
	if( kbactive )
	{
		kbreq.io_Command = KBD_REMRESETHANDLER;
		DoIO( &kbreq );
		CloseDevice( &kbreq );
	}
}

static int __asm __interrupt __saveds resethandler( register __a1 struct Task *mytask )
{
	inreset = 1;
	Signal( mytask, SIGBREAKF_CTRL_C );
//	SetTaskPri( mytask, 5 );
	return( 0 );
}

#define psout(x) if(outf)Write(outf,x,strlen(x))
void doresetcleanup( void )
{
	BPTR outf;

	if( !inreset )
		return;

	if( scr && isv37 )
	{
		outf = Open( "RAW:///120/MicroDot/SCREENMICRODOT", MODE_OLDFILE );
	}
	if( !outf )
		outf = Open( "RAW:///120/MicroDot", MODE_OLDFILE );

	psout( "Resetnotfall:\nEinstellungen speichern...\n" );
	if( ! ( prefs.flags2 & MDF2_NOPREFS ) )
	{
		freeinhalt();
		savebretter();
		saveprefs( currentprefsname );
		freebretter();
	}

	psout( "Caches leeren...\n" );
	flushbrettixall();
	ixc_exit();
#ifndef MDV20
	flushall();
#endif

	if( isv37 && MYPROC->pr_CurrentDir )
	{
		psout( "Filesystem flushen...\n" );
		DoPkt( ( ( struct FileLock * ) BADDR( MYPROC->pr_CurrentDir ) )->fl_Task, ACTION_FLUSH, 0, 0, 0, 0, 0 );
	}

	psout( "Fertig.\n" );
	Delay( 127 );

	kbreq.io_Command = KBD_RESETHANDLERDONE;
	DoIO( &kbreq );

	Wait( 0 );
}

ULONG mWait( ULONG sigs )
{
	ULONG rsigs = 0;

	while( ! ( rsigs & (~SIGBREAKF_CTRL_C ) ) )
	{
		rsigs = Wait( sigs | SIGBREAKF_CTRL_C );
		if( rsigs & SIGBREAKF_CTRL_C )
			doresetcleanup();
	}
	return( rsigs );
}

void mWaitPort( struct MsgPort *mp )
{
	Forbid();
	for(;;)
	{
		if( !IsListEmpty( &mp->mp_MsgList ) )
		{
			Permit();
			return;
		}
		mWait( 1L << mp->mp_SigBit );
	}
}

static void initkbresethandler( void )
{
	if( !resethandlerenabled )
		return;

	kbint.is_Node.ln_Name = "MicroDotKBDRInt";
	kbint.is_Code = resethandler;
	kbint.is_Data = FindTask( NULL );
	kbreq.io_Message.mn_ReplyPort = multiport;
	if( !OpenDevice( "keyboard.device", 0, &kbreq, 0 ) )
	{
		kbreq.io_Command = KBD_ADDRESETHANDLER;
		kbreq.io_Data = &kbint;
		DoIO( &kbreq );
		kbactive = TRUE;
	}
}

struct pathlist
{
	BPTR next;
	BPTR lock;
};

static int testseg( char *name )
{
	BPTR seglist;

	seglist = LoadSeg( name );

	if( seglist )
		UnLoadSeg( seglist );

	return( ( seglist ) ? 1 : 0 );
}

static int testseginlock( char *name, BPTR lock )
{
	int rc;
	BPTR oldcd;

	oldcd = CurrentDir( lock );
	rc = testseg( name );
	CurrentDir( oldcd );
	return( rc );
}

static void makefullname( char *name, BPTR dir, char *fullpath )
{
	if( !fullpath || !isv37 )
		return;

	NameFromLock( dir, fullpath, 256 );
	AddPart( fullpath, name, 256 );
}

int checkprograminpathfull( char *name, char *fullpath )
{
	char buffer[ 256 ], *p;
	BPTR cd;
	int rc;
	struct CommandLineInterface *cli;
	struct pathlist *pl;

	strcpy( buffer, name );
	p = strchr( buffer, ' ' );
	if( p )
		*p = 0;

	if( fullpath )
		strcpy( fullpath, name );

	/* Resident? */
	if( isv37 )
	{
		Forbid();
		if( FindSegment( buffer, NULL, FALSE ) )
		{
			Permit();
			return( 1 );
		}
		Permit();
	}

	/* Erst CD */
	if( testseg( buffer ) )
	{
		makefullname( name, MYPROC->pr_CurrentDir, fullpath );
		return( 1 );
	}

	/* dann C: */
	cd = Lock( "C:", SHARED_LOCK );
	rc = testseginlock( buffer, cd );
	if( rc )
		makefullname( name, cd, fullpath );
	UnLock( cd );

	if( rc )
		return( 1 );

	/* Cli? */
	cli = BADDR( MYPROC->pr_CLI );
	if( !cli )
		return( 0 );

	pl = BADDR( cli->cli_CommandDir );

	while( pl )
	{
		if( testseginlock( buffer, pl->lock ) )
		{
			makefullname( name, pl->lock, fullpath );
			return( 1 );
		}
		pl = BADDR( pl->next );	
	}

	return( 0 );
}

int checkprograminpath( char *name )
{
	return( checkprograminpathfull( name, NULL ) );
}

static ULONG __asm __saveds memhandlercode(	register __a0 struct MemHandlerData *mhd )
{
	flushbuffmem();
	flushbrettix();

	return( MEM_ALL_DONE );
}

static void addmemhandler( void )
{
	if( isv39 )
	{
		memhandler.is_Node.ln_Pri = 100;
		memhandler.is_Node.ln_Name = "MicroDot LowMem Handler";
		memhandler.is_Code = memhandlercode;

		AddMemHandler( &memhandler );
	}
}

static void remmemhandler( void )
{
	if( memhandler.is_Code )
		RemMemHandler( &memhandler );
}


#if 0
#ifdef MDV20
void *fopen( char *name, char *mode )
{
	BPTR f = NULL;

	switch( mode[ 0 ] )
	{
		case 'r':
		case 'R':
			f = Open( name, MODE_OLDFILE );
			break;

		case 'w':
		case 'W':
			f = Open( name, MODE_NEWFILE );
			break;

		case 'a':
		case 'A':
			f = Open( name, MODE_OLDFILE );
			if( f )
			{
				Seek( f, 0, OFFSET_END );
				Flush( f );
			}
			else
				f = Open( name, MODE_NEWFILE );
			break;
	}

	return( ( void * ) f );
}

int fseek( void *f, int offs, int mode )
{
	int m = OFFSET_CURRENT;

	switch( mode )
	{
		case 0:
			m = OFFSET_BEGINNING;
			break;
		case 2:
			m = OFFSET_END;
			break;
	}

	return( Seek( ( BPTR ) f, offs, m ) );
}
#endif
#endif

static BPTR logfile;
void __stdargs addlogfile( char *txt, ... )
{
	char buffer[ 512 + 2 ];
	char x[ 6 ];

	if( !prefs.do_logfile )
		return;

	if( !logfile )
	{
		logfile = Open( LOGNAME, MODE_OLDFILE );
		if( !logfile )
			logfile = Open( LOGNAME, MODE_NEWFILE );
		else
			Seek( logfile, 0, OFFSET_END );
	}
	if( !logfile )
		return;

	utunpk( time( 0 ), x );
	sprintf( buffer, "%02ld:%02ld:%02ld %02ld.%02ld.%02ld ",
		x[ 3 ], x[ 4 ], x[ 5 ],
		x[ 2 ], x[ 1 ], ( x[ 0 ] + 70 ) % 100
	);

//	replaceld( txt );
	dofmt( &buffer[ 18 ], txt, ( void * ) ( ( ( long ) &txt ) + 4 ) );
	strcat( buffer, "\n" );

	Write( logfile, buffer, strlen( buffer ) );
}

void displaybeep( void )
{
	DisplayBeep( scr );
}

void drawframe(struct RastPort *rp,int x,int y,int xs,int ys,int rec)
{
	sabd(rp,(rec)?1:2,0,JAM1);
	Move(rp,x,y+ys-1); Draw(rp,x,y); Draw(rp,x+xs-1,y);
	SetAPen(rp,(rec)?2:1);
	Move(rp,x+xs-1,y+1);
	Draw(rp,x+xs-1,y+ys-1);
	Draw(rp,x+1,y+ys-1);
}

void __stdargs preport(int l,int c,char *txt,...)
{
	char *p = ( l ) ? infotxt2 : infotxt1;
	struct IntuiText *it = ( l ) ? &infoitext2 : &infoitext1;
	int maxch = min( screenxsize / fontxsize, 256 );

	dofmt(p,txt,(void*)(((long)&txt)+4));
	if(strlen(p)<maxch) memset(&p[strlen(p)],32,maxch-strlen(p));
	p[ maxch ] = 0;

	it->FrontPen = c;
	PrintIText( w->RPort, it, infogadget.LeftEdge, infogadget.TopEdge );
}

/* Create Bevel Border */
struct Border *makebevelborder( int xs, int ys, BOOL recessed )
{
	struct Border *b1, *b2;
	UWORD  *vec1;
	UWORD  *vec2;

	xs--; ys--;

	/* First Part */

	b1 = LibAllocPooled( miscmempool, sizeof( *b1 ) );
	if( !b1 )
		return( NULL );
	vec1 = LibAllocPooled( miscmempool, 10 * 2 );
	if( !vec1 )
		return( NULL );
	b1->XY = vec1;
	b1->Count = resolution11 ? 3 : 5;
	b1->FrontPen = screenpens[ ( recessed ) ?  SHADOWPEN : SHINEPEN ];
	
	/* Start Upper Right! */
	vec1[0] = xs-1;
	vec1[5] = ys;

	vec1[6] = 1;
	vec1[7] = ys-1;

	vec1[8] = 1;
	vec1[9] = 1;

	/* Second Part */

	b2 = LibAllocPooled( miscmempool, sizeof( *b2 ) );
	if( !b1 )
		return( NULL );
	vec2 = LibAllocPooled( miscmempool, 10 * 2 );
	if( !vec2 )
		return( NULL );
	b2->XY = vec2;
	b2->Count = resolution11 ? 3 : 5;
	b2->FrontPen = screenpens[ ( recessed ) ? SHINEPEN : SHADOWPEN ];
	b1->NextBorder = b2;
	
	/* Start Lower Left! */
	vec2[0] = 1;
	vec2[1] = ys;

	vec2[2] = xs;
	vec2[3] = ys;

	vec2[4] = xs;

	vec2[6] = xs-1;
	vec2[7] = 1;

	vec2[8] = xs-1;
	vec2[9] = ys-1;

	return( b1 );
}


/* Create Arrow Border */
static struct Border *makearrowborder( int xs, int ys, BOOL up, BOOL recessed )
{
	struct Border *b0, *b1, *b2;
	UWORD *vec1;

	b0 = makebevelborder( xs, ys, recessed );
	if( !b0 )
		return( NULL );
	xs--; ys--;

	b1 = LibAllocPooled( miscmempool, sizeof( *b1 ) );
	if( !b1 )
		return( NULL );

	vec1 = LibAllocPooled( miscmempool, 6 * 2 );
	if( !vec1 )
		return( NULL );

	b1->XY = vec1;
	b1->Count = 3;
	b1->FrontPen = screenpens[ TEXTPEN ];
	
	if( up )
	{
		vec1[0] = 3;
		vec1[1] = ys - 2;

		vec1[2] = xs / 2;
		vec1[3] = 2;

		vec1[4] = xs-4;
		vec1[5] = ys - 2;
	}
	else
	{
		vec1[0] = 3;
		vec1[1] = 2;

		vec1[2] = xs / 2;
		vec1[3] = ys - 2;

		vec1[4] = xs-4;
		vec1[5] = 2;
	}

	b1->NextBorder = b0;

	b2 = LibAllocPooled( miscmempool, sizeof( *b2 ) );
	if( !b2 )
		return( NULL );
	*b2 = *b1;
	b2->LeftEdge++;
	b2->NextBorder = b1;

	return( b2 );
}

static ULONG dobj_x = NO_ICON_POSITION, dobj_y = NO_ICON_POSITION;
void doiconify( void )
{
	struct DiskObject *dobj = GetDiskObjectNew( progname );
	void *appicon;
	struct MsgPort *mp;
	struct AppMessage *apm;
	long sig, psig;
	int Done = FALSE;

	if( !dobj )
	{
		displaybeep();
		return;
	}

	dobj->do_CurrentX = dobj_x;
	dobj->do_CurrentY = dobj_y;

	mp = CreateMsgPort();
	psig = 1 << mp->mp_SigBit;

	//Printf( "mp %lx psig %lx\n", mp, mp->mp_SigBit );

	appicon = AddAppIcon( 42, NULL,
		"-MicroDot-",
		mp,
		NULL,
		dobj,
		TAG_DONE
	);

	if( !appicon )
	{
		DeletePort( mp );
		FreeDiskObject( dobj );
		askreq( "Konnte Workbench-Piktogramm\nnicht anlegen.", "Wartestellung nicht möglich" );
		return;
	}

	savemenustate( w->MenuStrip );
	closegui();

	while( !Done )
	{
		sig = mWait( SIGBREAKF_CTRL_F | psig );
		if( sig & psig )
		{
			while( ( apm = ( struct AppMessage * ) GetMsg( mp ) ) )
			{
				if( !apm->am_NumArgs )
					Done = TRUE;
				ReplyMsg( apm );
			}
		}
		if( sig & SIGBREAKF_CTRL_F )
			Done = TRUE;
	}

	/*dobj_x = dobj->do_CurrentX;
	dobj_y = dobj->do_CurrentY;*/

	RemoveAppIcon( appicon );
	DeleteMsgPort( mp );
	FreeDiskObject( dobj );

	//Printf( "ok, opengui\n" );
	opengui();
	resetmenustate( w->MenuStrip );
}

/* Draw Clock every second */
void __saveds clockfunc( void )
{
	struct Window *clockw;
	struct RastPort *crp;
	char x[6];
	char buffer[10];
	ULONG sigs, tsig;
	struct timerequest treq;
	struct Gadget *g;
	int delay = ( prefs.clockmode == CLOCKMODE_HHMM ) ? 30 : 1;
	int txtsz = ( prefs.clockmode == CLOCKMODE_HHMM ) ? 5 : 8;
	int width;
	int height;
	char *fmtstring = ( prefs.clockmode == CLOCKMODE_HHMM ) ? "%02ld:%02ld " : "%02ld:%02ld:%02ld ";
	struct IntuiText lit;
	static struct NewWindow cnw = { 0, 1, 0, 0, 
		0xff, 0xff, NULL,
		BORDERLESS | RMBTRAP | NOCAREREFRESH,
		NULL, NULL, NULL, NULL, NULL,
		0, 0, 0, 0,
		CUSTOMSCREEN
	};

	lit.IText 	  = ( prefs.clockmode == CLOCKMODE_HHMM ) ? "00:00" : "00:00:00";
	lit.ITextFont = &screenfontta;
	width  = IntuiTextLength( &lit ) + 12;
	height = screenfontta.ta_YSize;

	/* Open Window */

	g = AllocMem( sizeof( *g ), MEMF_CLEAR );
	g->Width 	= width;
	g->Height	= height;
	g->Flags 	= GFLG_GADGHNONE;
	g->GadgetType = GTYP_SDRAGGING;

	cnw.Screen 		= scr;
	cnw.LeftEdge 	= scr->Width - ( width + 28 );
	if( !isv37 )
		cnw.LeftEdge -= 32;
	cnw.FirstGadget = g;
	cnw.Width		= width;
	cnw.Height		= height;

	clockw 			= OpenWindow( &cnw );
	crp 			= clockw->RPort;

	SetRast( crp, screenpens[ BARBLOCKPEN ] );

	treq.tr_node.io_Message.mn_ReplyPort = CreatePort( NULL, NULL );
	tsig = 1<<treq.tr_node.io_Message.mn_ReplyPort->mp_SigBit;
	OpenDevice( "timer.device", UNIT_VBLANK, &treq, 0 );

	sabd( crp, screenpens[ BARDETAILPEN ], screenpens[ BARBLOCKPEN ], JAM2 );

	for(;;)
	{
		utunpk( time( NULL ), x );
		/* Draw clock */
		sprintf(buffer, fmtstring,
				x[3], x[4], x[5] );
		Move( crp, 12, crp->Font->tf_Baseline );
		Text( crp, buffer, txtsz + 1 );

		/* Queue Timer */
		treq.tr_time.tv_secs 	= delay;
		treq.tr_time.tv_micro 	= 0;
		treq.tr_node.io_Command = TR_ADDREQUEST;

		SendIO( &treq );

		/* Wait for timer or sig */
		sigs = Wait( tsig | SIGBREAKF_CTRL_C );

		if( sigs & SIGBREAKF_CTRL_C )
			break;

		WaitIO( &treq );
	}

	CloseWindow( clockw );

	FreeMem( g, sizeof( *g ) );

	AbortIO( &treq );
	WaitIO( &treq );

	CloseDevice( &treq );
	DeletePort( treq.tr_node.io_Message.mn_ReplyPort );

	clocktask = NULL;
}

void startclock( void )
{
	if( !clocktask && prefs.clockmode != CLOCKMODE_NONE && !wbwindow )
		clocktask = CreateTask( "MicroDot Clock Server", 9, clockfunc, 3200 );
}

void stopclock( void )
{
	if( clocktask )
		Signal( clocktask, SIGBREAKF_CTRL_C );
}

static void closewindow( void )
{
	int c;

	closeguide();

	if( listfont )
		CloseFont( listfont );

	if( wbwindow && w )
	{
		prefs.window_x  = w->LeftEdge;
		prefs.window_y  = w->TopEdge;
		prefs.window_xs = w->Width;
		prefs.window_ys = w->Height;

		if( appwindow )
		{
			RemoveAppWindow( appwindow );
			DeleteMsgPort( appwindowmp );

			appwindow = NULL;
			appwindowmp = NULL;
			appwindowsig = 0;
		}

	}
	stopclock();
	while( clocktask )
		Delay( 17 );

	MYPROC->pr_WindowPtr = oldprwindowptr;
	if( w )
	{
		ClearMenuStrip( w );
		CloseWindow( w );
		w = NULL;
	}

	if( menustrip )
		LibDeletePool( menurkey );

	if( scr )
	{
		if( wbwindow )
		{
			if( isv37 )
				UnlockPubScreen( 0, scr );
		}
		else
		{
			for( ;; )
			{
				c = CloseScreen( scr );
				if( c || !isv37 )
					break;

				rtEZRequestTags(	"Bitte schließen Sie alle Besucherfenster\nauf dem MicroDot-Bildschirm.",
								"Weiter",
								NULL, NULL, RT_Screen, scr, TAG_DONE );
			}
		}
		scr = NULL;
	}

	if( rinfo )
		rtFreeRequest( rinfo );
}

/*static void report( char *txt )
{
	kputs( txt );
	Delay( 50 );
}
*/

void cleanup( void )
{
	int c;

	remmemhandler();

	if( logfile )
	{
		addlogfile( "EXIT MicroDot" );
		Close( logfile );
	}

	if( ! ( prefs.flags2 & MDF2_NOPREFS ) )
	{
		if( wbwindow && w )
		{
			prefs.window_x  = w->LeftEdge;
			prefs.window_y  = w->TopEdge;
			prefs.window_xs = w->Width;
			prefs.window_ys = w->Height;
		}

		freeinhalt();
		savebretter();
		saveprefs( currentprefsname );
		freebretter();
	}

	flushbrettixall();
	ixc_exit();
	cleanuparexx();

	closegui();

	/* Sysnode installed? */
	if( mymdsysnode.n.mln_Succ )
	{
		struct mdresource *mdr = OpenResource( MDRS_NAME );
		ObtainSemaphore( &mdr->sem );
		Remove( ( struct Node * ) &mymdsysnode );
		ReleaseSemaphore( &mdr->sem );
	}

	UnLock( mymdsysnode.datapath );
	UnLock( mymdsysnode.transferpath );
	UnLock( mymdsysnode.progdir );

	exitbuffmem();

	for( c = 0; c < 7; c++ )
	{
		if( fr[ c ] )
			rtFreeRequest( fr[ c ] );
	}

	if( chipmempool )
		LibDeletePool( chipmempool );

	if( keyseglist )
		UnLoadSeg( keyseglist );

	if( ReqToolsBase )
		CloseLibrary( ReqToolsBase );

	if( LocaleBase )
		CloseLibrary( LocaleBase );

	if( DataTypesBase )
		CloseLibrary( DataTypesBase );

	if( RexxSysBase )
		CloseLibrary( RexxSysBase );

	if( WhatIsBase )
		CloseLibrary( WhatIsBase );

	if( GadToolsBase )
		CloseLibrary( GadToolsBase );

	if( KeymapBase )
		CloseLibrary( KeymapBase );

	if( XpkBase )
		CloseLibrary( XpkBase );

	if( WorkbenchBase )
		CloseLibrary( WorkbenchBase );

	CloseFont( &mdmicroFont );
	if( isv37 )
		StripFont( &mdmicroFont );
	RemFont( &mdmicroFont );

	/*report( "before freeargs\n ");*/

	if( rda )
	{
		FreeArgs( rda );
		FreeDosObject( DOS_RDARGS, rda );
	}

	/*report( "after freeargs\n ");*/

	if( resetcurrentinput )
	{
		BPTR io;

		if( isv37 )
		{
			io = SelectInput( NULL );
			if( io )
				Close( io );
		}
		else
		{
			Close( MYPROC->pr_CIS );
			MYPROC->pr_CIS = NULL;
		}
	}
	if( resetcurrentoutput )
	{
		BPTR io;

		if( isv37 )
		{
			io = SelectOutput( NULL );
			if( io )
				Close( io );
		}
		else
		{
			Close( MYPROC->pr_COS );
			MYPROC->pr_COS = NULL;
		}
	}

	/*report( "uncd\n" );*/

	freelockstack();

	remkbresethandler();

	if( multiport )
		DeletePort( multiport );

	if( miscmempool )
		LibDeletePool( miscmempool );

	/*report( "exit\n" );*/
}

void exiterror(char *error)
{
	BPTR f;

	if( isv37 )
		f = Open( "CON:///100/MicroDot-Fehler!/WAIT/CLOSE/INACTIVE", MODE_NEWFILE );
	else
		f = Open( "CON:0/0/640/100/MicroDot-Fehler!", MODE_NEWFILE );

	if( f )
	{
		Write( f, "MicroDOT: ", 10 );
		Write( f, error, strlen( error ) );
		Write( f, "\n\x07", 2 );
		if( !isv37 )
		{
			char dummy;
			Write( f, "[RETURN]", 8 );
			Read( f, &dummy, 1 );
		}
		Close( f );
	}
	exit(10);
}

static struct MenuItem *currentitem, *subparent, *oldci;
static struct Menu *currentmenu;
static struct MenuItem *escswitchmenu, *escswitchmenu1, *escswitchmenu2;
static USHORT menux,itemy, olditemy, __padddding;
static void addmenu(char *title)
{
	struct Menu *new,*p;
	struct IntuiText it;

	memset( &it, 0, sizeof( it ) );
	it.ITextFont 	= &menufontta;
	it.IText		= title;

	currentitem = subparent = NULL;
	new = LibAllocPooled( menurkey, sizeof( struct Menu ) );
	if( !new )
	{
		displaybeep();
		return;
	}
	new->LeftEdge = menux;
	new->Width 	  = ( IntuiTextLength( &it ) + menufontta.ta_YSize + 2 ) & ~1;
	menux		  += new->Width;
	new->TopEdge  = 0;
	new->Height   = 11;
	new->Flags    = MENUENABLED;
	new->MenuName = title;

	itemy = 0;
	p = menustrip;
	if( !p )
	{
		menustrip = new;
	}
	else
	{
		while( p->NextMenu )
			p = p->NextMenu;
		p->NextMenu = new;
	}
	currentmenu = new;
}

#define MFRVAL(x) (((x)<<8)|8)
#define MFRINITSUB 4
#define MFRSHIFT (1<<16)

struct Image *makemenubarimage( int xs )
{
	UWORD *imagedata;
	UWORD planes[ 8 ], planes2[ 8 ];
	int c, d, ws = ( ( xs + 15 ) / 16 );
	struct Image *im = LibAllocPooled( menurkey, sizeof( *im ) );
	int dp = scr->RastPort.BitMap->Depth;

	imagedata   	= allocchipmem( ws * 4 * dp );
	im->TopEdge 	= 2;
	im->Depth   	= dp;
	im->Height   	= 2;
	im->Width   	= xs;
	im->PlanePick	= ( 1 << dp ) - 1;
	im->ImageData	= imagedata;

	for( c = 0; c < dp; c++ )
	{
		planes[ c ] = 0;
		planes2[ c ] = 0;

		if( screenpens[ BARDETAILPEN ] & ( 1 << c ) )
		{
			planes[ c ] |= 0xdddd;
			planes2[ c ] |= 0x7777;
		}
		if( screenpens[ BARBLOCKPEN ] & ( 1 << c ) )
		{
			planes[ c ] |= ~0xdddd;
			planes2[ c ] |= ~0x7777;
		}
	}

	for( c = 0; c < ws; c++ )
	{
		for( d = 0; d < dp; d++ )
		{
			imagedata[ c + ( ( d * 2 ) * ws ) ] 	   = planes[ d ];
			imagedata[ c + ( ( ( d * 2 ) + 1 ) * ws )] = planes2[ d ];
		}
	}

	return( im );
}

//static UBYTE menustates[ 1024 ];
static UBYTE *menustates;

ALLOCSTATIC( menustates, 1024, MEMF_CLEAR )

void savemenustate( struct Menu *menu )
{
	UBYTE *mp = menustates;
	struct MenuItem *item, *sub;

	while( menu )
	{
		*mp++ = menu->Flags & MENUENABLED;
		item = menu->FirstItem;
		while( item )
		{
			*mp++ = item->Flags & ITEMENABLED;
			sub = item->SubItem;
			while( sub )
			{
				*mp++ = sub->Flags & ITEMENABLED;
				sub = sub->NextItem;
			}
			item = item->NextItem;
		}
		menu = menu->NextMenu;
	}
}

void resetmenustate( struct Menu *menu )
{
	UBYTE *mp = menustates;
	struct MenuItem *item, *sub;

	while( menu )
	{
		if( *mp++ )
			menu->Flags |= MENUENABLED;
		else
			menu->Flags &= ~MENUENABLED;
		item = menu->FirstItem;
		while( item )
		{
			if( *mp++ )
				item->Flags |= ITEMENABLED;
			else
				item->Flags &= ~ITEMENABLED;
			sub = item->SubItem;
			while( sub )
			{
				if( *mp++ )
					sub->Flags |= ITEMENABLED;
				else
					sub->Flags &= ~ITEMENABLED;
				sub = sub->NextItem;
			}
			item = item->NextItem;
		}
		menu = menu->NextMenu;
	}
}



static int menumono;
static void addmenuitem(char *title,ULONG commandkey,ULONG flags)
{
	struct MenuItem *new;
	struct IntuiText *it;
	ULONG xs = 0;
	UBYTE *rvalp;

	if( title )
	{
		struct IntuiText lit;
		lit.IText = title;
		lit.ITextFont = &menufontta;
		xs = IntuiTextLength( &lit ) + 4;
	}
	if(commandkey) xs += COMMWIDTH + 12;
	if(flags&0x3) xs += CHECKWIDTH;

	new = LibAllocPooled( menurkey, sizeof( struct MenuItem ) + 2 );
	rvalp = (UBYTE*)(((long)new)+sizeof(struct MenuItem));
	if( flags & 8 )
	{
		*rvalp++=(flags&MFRSHIFT)?0xff:0x42;
		*rvalp=flags>>8;
	}

	new->Flags = ITEMENABLED;
	if(title) new->Flags|=HIGHCOMP;
	if(flags&1) new->Flags|=MENUTOGGLE|CHECKIT;
	if(flags&2) new->Flags|=CHECKED;

	if(commandkey && ((long)commandkey)<255)
	{
		new->Command=(BYTE)commandkey;
		new->Flags|=COMMSEQ;
	}

	new->LeftEdge= ( subparent ) ? 32 : 2;
	new->TopEdge = itemy;
	itemy+=(title)?menufontta.ta_YSize+2:6;
	new->Height=(title)?menufontta.ta_YSize+2:6;
	new->Width=xs;

	if( title )
	{
		it = LibAllocPooled( menurkey, sizeof( struct IntuiText ) );
		new->ItemFill = it;
		new->Flags |= ITEMTEXT;
		it->DrawMode = JAM1;
		if( menumono )
		{
			it->FrontPen=0;
			it->BackPen=1;
		}
		else
		{
			it->FrontPen = screenpens[ BARDETAILPEN ];
			it->BackPen = screenpens[ BARBLOCKPEN ];
		}
		it->LeftEdge=(flags&0x3)?CHECKWIDTH:0;
		it->TopEdge=(title)?1:-1;
		it->ITextFont=(!title)?&menufontta_bold:&menufontta;
		it->IText=title;
		if(((long)commandkey)>254)
		{
			it->NextText=LibAllocPooled(menurkey,sizeof(struct IntuiText));
			it = it->NextText;
			it->BackPen = screenpens[ BARBLOCKPEN ];
			it->FrontPen = screenpens[ BARDETAILPEN ];
			it->DrawMode=JAM1;
			it->TopEdge=1;
			it->ITextFont=&menufontta_bold;
			it->IText=(char*)commandkey;
		}
		else if( flags & MFRINITSUB )
		{
			it->NextText = LibAllocPooled(menurkey,sizeof(struct IntuiText));
			it = it->NextText;
			it->BackPen = screenpens[ BARBLOCKPEN ];
			it->FrontPen = screenpens[ BARDETAILPEN ];
			it->DrawMode=JAM1;
			it->TopEdge=1;
			it->ITextFont=&menufontta;
			it->IText = "»";
		}
	}
	else
	{
		if( menumono )
			new->ItemFill = (APTR)-1;
	}

	if( currentitem )
	{
		currentitem->NextItem = new;
	}
	else
	{
		if( subparent )
		{
			subparent->SubItem = new;
		}
		else
		{
			currentmenu->FirstItem = new;
		}
	}

	if( flags & MFRINITSUB )
	{
		oldci = new;
		subparent = new;
		olditemy = itemy;
		itemy = 0;
		currentitem = NULL;
	}
	else
	{
		currentitem = new;
	}
}

static void addendsub( void )
{
	currentitem = oldci;
	itemy = olditemy;
	subparent = NULL;
}

static void layoutmenu( struct MenuItem *mi )
{
	struct MenuItem *m;
	USHORT maxx;
	struct IntuiText *it;
	struct Image *barim;

	m = mi;
	maxx = 0;
	while( m )
	{
		if( m->SubItem )
			layoutmenu( m->SubItem );

		if( ( m->Width > maxx ) && ( m->Flags & ITEMTEXT ) )
			maxx = m->Width;

		m=m->NextItem;
	}
	m = mi;
	barim = NULL;
	while( m )
	{
		m->Width=maxx;
		if( m->Flags & ITEMTEXT )
		{
			it=m->ItemFill;
			if( it->NextText )
			{
				it=it->NextText;
				it->LeftEdge=maxx-3-IntuiTextLength( it );
			}
		}
		else
		{
			if( !barim )
				barim = makemenubarimage( maxx );
			if( m->ItemFill )
			{
				barim->PlanePick	= 0;
				barim->Depth		= 1;
			}
			m->ItemFill = barim;
		}
		m=m->NextItem;
	}
}


static void layoutmenus(void)
{
	struct Menu *mp = menustrip;

	while( mp )
	{
		layoutmenu( mp->FirstItem );
		mp=mp->NextMenu;
	}
}

static char titletext[160];
void settitletxt( void )
{
	char psrxinfo[ 80 ];
	char *mypubname = wbwindow ? NULL : pubscreenname;

	psrxinfo[ 0 ] = 0;
	if( mypubname || rexxhost )
	{
		if( mypubname && !rexxhost && strcmp( mypubname, "MICRODOT" ) )
			sprintf( psrxinfo, "[S:%s] ", mypubname );
		else if( !mypubname && rexxhost && strcmp( rexxhost->portname, "MICRODOT" ) )
			sprintf( psrxinfo, "[RX:%s] ", rexxhost->portname );
		else if( strcmp( rexxhost->portname, "MICRODOT" ) && strcmp( mypubname, "MICRODOT" ) )
			sprintf( psrxinfo, "[S:%s/RX:%s] ", mypubname, rexxhost->portname );
	}


#ifdef MDV20
	if( !prefs.username[0] )
		sprintf( titletext, "MicroDot020 " MDVER " - %snicht konfiguriert",psrxinfo);
	else
		sprintf( titletext, "MicroDot020 " MDVER " - %s%s@%s%s (%s)",psrxinfo,prefs.username,ISRFC ? prefs.pointname : prefs.boxname,prefs.boxdomain,prefs.userrealname);
#else
	if( !prefs.username[0] )
		sprintf( titletext, "MicroDot " MDVER " - %snicht konfiguriert",psrxinfo);
	else
		sprintf( titletext, "MicroDot " MDVER " - %s%s@%s%s (%s)",psrxinfo,prefs.username,ISRFC ? prefs.pointname : prefs.boxname,prefs.boxdomain,prefs.userrealname);
#endif

	if( w )
	{
		if( wbwindow )
			SetWindowTitles( w, titletext, WBSCREENTITLE );
		else
			SetWindowTitles( w, (UBYTE *) -1, titletext );
	}
}

extern int bl_maxname, bl_maxcomment;
static void calcblistsize( void )
{
	int commentsize;	/* 32 Zeichen max */

	brettlist_namesize = screencols - 22;
	commentsize = min( 31, brettlist_namesize / 5 );
	commentsize = min( commentsize, bl_maxcomment );

	brettlist_namesize -= commentsize;
	if( brettlist_namesize > bl_maxname )
		brettlist_namesize = bl_maxname;

	if( screencols - brettlist_namesize - 23 > bl_maxcomment )
		brettlist_namesize += screencols - brettlist_namesize - 23 - bl_maxcomment;

	if( brettlist_namesize < 10 )
		brettlist_namesize = 10;
}

int ml_bet, ml_kb, ml_date;
static void calcmlistsize( void )
{
	int space = screencols - 79;

	ml_bet = 31;
	ml_kb = 5;
	ml_date = 5;

	if( space <= 0 )
	{
		ml_bet -= min( ( -space ) / 2, 15 );
		return;
	}

	while( space-- > 0 )
	{
		if( ml_bet < 42 )
			ml_bet++;
		else if( !( space % 5 ) && ( ml_kb < 11 ) )
			ml_kb++;
		else if( !( space % 4 ) && ( ml_date < 11 ) )
			ml_date++;
		else if( ml_bet < 48 )
			ml_bet++;
	}
}

static void initlinestarts( void );
void recalcwindowsize( void )
{
	if( !wbwindow )
	{
		screenlines = ( scr->Height - topoffs ) / fontysize;
		calcblistsize();
		calcmlistsize();
		initlinestarts();
		return;
	}
	screenxsize = w->GZZWidth + 16;
	screenlines = (w->GZZHeight-topoffs) / fontysize;
	screencols  = w->GZZWidth / fontxsize;
	calcblistsize();
	calcmlistsize();
	initlinestarts();
}

static void rexxlist2menu( struct List *l, int fkey )
{
	struct rexxcmd *cmd = ( struct rexxcmd * ) l->lh_Head;
	int fkc = 0;
	static char *fkeyn[] = { "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10" };
	static char *sfkeyn[] = { "*F1", "*F2", "*F3", "*F4", "*F5", "*F6", "*F7", "*F8", "*F9", "*F10" };

	while( cmd->n.ln_Succ )
	{
		addmenuitem( cmd->name, ( ULONG ) ( fkc < 5 ? ( fkeyn[ fkey + fkc ] ): ( fkc < 10 ) ? sfkeyn[ fkey + fkc - 5 ] : 0), fkc < 5 ? MFRVAL( ( fkc + fkey + 0x50 ) ) : ( fkc < 10 ) ? MFRVAL( + fkc - 5 + fkey + 0x50 ) | MFRSHIFT : 0 );
		fkc++;
		cmd = ( struct rexxcmd * ) cmd->n.ln_Succ;
	}
}

void calcmaxpen( void )
{
	int maxpen = 0;
	int c;

	if( !isv39 )
		return;

	prefs.pens[ PEN_QUOTE ] = 0;
	for( c = 0; c < 8; c++ )
	{
		if( prefs.pens[ c * 3 ] > maxpen )
			maxpen = prefs.pens[ c * 3 ];
		if( prefs.pens[ c * 3 + 1 ] > maxpen )
			maxpen = prefs.pens[ c * 3 + 1 ];
	}
	for( c = 0; c < 7; c++ )
	{
		if( prefs.quotepens[ c ] > maxpen )
			maxpen = prefs.quotepens[ c ];
	}
	SetMaxPen( rp, maxpen );
}

extern struct BitMap addBitMap;

static void openwindow(void)
{
	static USHORT pens[]={0xffff,0xffff};
	struct Border *b;
	struct DrawInfo *dri;
	struct ExtNewWindow nw;
	static char psn[ 16 ];
	int screencount = 0;
	ULONG soerror;

	/* Copy fresh NewWindow structure */
	nw = nw2;

	settitletxt();

	if( !wbwindow )
	{
		if( isv37 )
		{
			/* Use WB Pens */
/*			scr = LockPubScreen( NULL );
			if( scr )
			{
				dri = GetScreenDrawInfo( scr );
				if( dri )
				{
					penp = dri->dri_Pens;
					FreeScreenDrawInfo( scr, dri );
				}
				UnlockPubScreen( NULL, scr );
			}*/

			pubscreenname = psn;

screenopenretry:
			if( !screencount )
				strcpy( psn, "MICRODOT" );
			else
				sprintf( psn, "MICRODOT.%ld", screencount );
			
			screencount++;
			if( scr = LockPubScreen( psn ) ) 
			{
				UnlockPubScreen( NULL, scr );
				goto screenopenretry;
			}

			scr=OpenScreenTags( NULL,
				ModeNotAvailable( prefs.displayid ) ? TAG_IGNORE : SA_DisplayID, prefs.displayid,
				SA_LikeWorkbench, TRUE,
				(prefs.oscantype > 0 && prefs.oscantype < 4 ) ? SA_Overscan : TAG_IGNORE, prefs.oscantype,
				SA_Width, ( prefs.swidth >= 640 ) ? prefs.swidth : 640,
				SA_Height, ( prefs.sheight >= 256 ) ? prefs.sheight : 256,
				SA_Depth, ( prefs.screendepth >= 1 ) ? prefs.screendepth : 2,
				SA_Title, titletext,
				SA_Pens, &pens,
				SA_Font, &screenfontta,
				SA_PubName, psn,
				SA_AutoScroll, TRUE,
				SA_FullPalette, TRUE,
				SA_ShowTitle, TRUE,
				SA_Interleaved, TRUE,
				SA_ErrorCode, &soerror,
				TAG_DONE
			);

			if( !scr && ( soerror == OSERR_PUBNOTUNIQUE ) )
			{
				goto screenopenretry;

			}

			if( scr )
				PubScreenStatus( scr, 0 );
		}
		else
		{
			ns.Height = ( prefs.flags & MDF_INTERLACE ) ? 512 : 256;
			ns.DefaultTitle = titletext;
			if( prefs.flags & MDF_INTERLACE )
				ns.ViewModes |= LACE;
			else
				ns.ViewModes &= ~LACE;
			scr = OpenScreen( &ns );
		}
		if( !scr )
			exiterror( "kann Screen nicht öffnen" );

		/* Farben setzen */
		if( prefs.usecustomcolors )
			setcolors( scr );
	}
	else
	{
		/*slowtext = TRUE;*/
		if( isv37 )
		{
			if( !pubscreenname )
				pubscreenname = "Workbench";
			scr = LockPubScreen( pubscreenname );
			if( !scr )
				scr = LockPubScreen( NULL );
		}
		else
			scr = (struct Screen *) OpenWorkBench();
	}

	/* Init Pens, 1.3 Style */
	if( !isv37 )
	{
		screenpens[ DETAILPEN ] = scr->DetailPen;
		screenpens[ BLOCKPEN ]  = scr->BlockPen;
		screenpens[ TEXTPEN ]   = 1;
		screenpens[ SHINEPEN ]  = 1;
		screenpens[ SHADOWPEN ] = 2;
		screenpens[ FILLPEN ]	  = 3;
		screenpens[ FILLTEXTPEN ] = 2;
		screenpens[ BACKGROUNDPEN ] = 0;
		screenpens[ HIGHLIGHTTEXTPEN ] = 3;

		screenpens[ BARDETAILPEN ] = screenpens[ DETAILPEN ];
		screenpens[ BARBLOCKPEN ] = screenpens[ BLOCKPEN ];

		resolution11 = prefs.flags & MDF_INTERLACE;

	}
	/* 2.0, obtain Pens via DrawInfo */
	else
	{
		dri = GetScreenDrawInfo( scr );
		if( dri )
		{
			if( dri->dri_Version >= 2 )
			{
				memcpy( screenpens, dri->dri_Pens, 11 * 2 );
			}
			else
			{
				memcpy( screenpens, dri->dri_Pens, 9 * 2 );
				screenpens[ BARDETAILPEN ] = screenpens[ DETAILPEN ];
				screenpens[ BARBLOCKPEN ] = screenpens[ BLOCKPEN ];
			}

			if( dri->dri_Resolution.X )
			{
				if( ( dri->dri_Resolution.Y / dri->dri_Resolution.X ) < 2 )
					resolution11 = TRUE;
				else
					resolution11 = FALSE;
			}
			FreeScreenDrawInfo( scr, dri );
		}
	}

	menufontta = *scr->Font;
	menufontta_bold = menufontta;
	menufontta_bold.ta_Style |= FSF_BOLD;

	nw.Screen = scr;
	nw.Height = scr->Height;

	topoffs = scr->BarHeight + 6 + (fontysize * 2 );
	topborderoffs = scr->WBorTop + fontysize - 10;

	screenxsize = nw.Width = scr->Width;
	screenlines = ( scr->Height - topoffs ) / fontysize;

	if( wbwindow )
	{
		nw.Flags &= ~ ( WFLG_BORDERLESS | WFLG_BACKDROP );
		nw.Flags |= WFLG_GIMMEZEROZERO | WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_SIZEGADGET | WFLG_CLOSEGADGET | WFLG_SIZEBRIGHT | WFLG_SIZEBBOTTOM;
		nw.Title = titletext;

		if( prefs.window_xs && prefs.window_ys )
		{
			nw.Height = prefs.window_ys;
			nw.Width = prefs.window_xs;
			nw.TopEdge = prefs.window_y;
			nw.LeftEdge = prefs.window_x;
		}

		topoffs = fontysize * 2 + 4 + 1;
		topborderoffs = -10;
	}

	if( wbwindow )
	{
		/*propinfo.Flags &= ~PROPBORDERLESS;*/
		scrollgad.Width = 10;
		scrollgad.Activation |= GACT_RIGHTBORDER;
		scrollgad.Flags |= GFLG_RELRIGHT | GFLG_RELHEIGHT;
		scrollgad.GadgetType |= GTYP_GZZGADGET;
		scrollgad.TopEdge = scr->WBorTop + scr->Font->ta_YSize + 2;
		scrollgad.LeftEdge = -13;
		scrollgad.Height = -scrollgad.TopEdge - 11 - 20;

		Pfeil1Gadg.Activation |= GACT_RIGHTBORDER;
		Pfeil1Gadg.Flags |= GFLG_RELRIGHT | GFLG_RELBOTTOM;;
		Pfeil1Gadg.Width = 18;
		Pfeil1Gadg.LeftEdge = -17;
		Pfeil1Gadg.TopEdge  = -9 - 18;
		Pfeil1Gadg.GadgetType |= GTYP_GZZGADGET;

		Pfeil2Gadg.Activation |= GACT_RIGHTBORDER;
		Pfeil2Gadg.Flags |= GFLG_RELRIGHT | GFLG_RELBOTTOM;
		Pfeil2Gadg.Width = 18;
		Pfeil2Gadg.LeftEdge = -17;
		Pfeil2Gadg.TopEdge  = -9 - 9;
		Pfeil2Gadg.GadgetType |= GTYP_GZZGADGET;

		if( prefs.flags & MDF_GADGETS )
		{
			gadgetlistcount = 5;
			Pfeil1Gadg.NextGadget = &bottomextendgadget;
			bottomextendgadget.Width = - ( scr->WBorLeft + scr->WBorRight + 32 );
			bottomextendgadget.Height = ( prefs.gadfontheight + 4 ) * 2;
			bottomextendgadget.TopEdge = -bottomextendgadget.Height;
		}
		else
		{
			gadgetlistcount = 4;
			Pfeil1Gadg.NextGadget = NULL;
			nw.Flags &= ~WFLG_SIZEBBOTTOM;
		}

		infoborder2.NextBorder = NULL;
	}
	else
	{
		scrollgad.TopEdge = topoffs + 2;
		scrollgad.Height = scr->Height - topoffs - 18 - 4;
		scrollgad.LeftEdge = screenxsize - 13;

		Pfeil1Gadg.TopEdge	= scrollgad.Height+topoffs + 4;
		Pfeil2Gadg.TopEdge	= Pfeil1Gadg.TopEdge+9;
		Pfeil1Gadg.LeftEdge	= scrollgad.LeftEdge-1 - 1;
		Pfeil2Gadg.LeftEdge	= scrollgad.LeftEdge-1 - 1;
		Pfeil1Gadg.Width 	= 15;
		Pfeil2Gadg.Width 	= 15;

		Pfeil1Gadg.NextGadget = NULL;
		scrollgad.Width = 11;
		scrollgad.Activation &= ~GACT_RIGHTBORDER;
		scrollgad.Flags &= ~ ( GFLG_RELRIGHT | GFLG_RELHEIGHT );
		scrollgad.GadgetType &= ~GTYP_GZZGADGET;

		Pfeil1Gadg.Activation &= ~GACT_RIGHTBORDER;
		Pfeil1Gadg.Flags &= ~( GFLG_RELRIGHT | GFLG_RELBOTTOM );
		Pfeil1Gadg.GadgetType &= ~GTYP_GZZGADGET;

		Pfeil2Gadg.Activation &= ~GACT_RIGHTBORDER;
		Pfeil2Gadg.Flags &= ~( GFLG_RELRIGHT | GFLG_RELBOTTOM );
		Pfeil2Gadg.GadgetType &= ~GTYP_GZZGADGET;

		b = makebevelborder( 15, scrollgad.Height + 4, FALSE );
		b->LeftEdge				= scrollgad.LeftEdge - 2;
		b->NextBorder->LeftEdge = scrollgad.LeftEdge - 2;
		b->TopEdge				= scrollgad.TopEdge - 2;
		b->NextBorder->TopEdge  = scrollgad.TopEdge - 2;
		infoborder2.NextBorder  = b;
	}

	infoborder1.FrontPen = screenpens[ SHADOWPEN ];
	infoborder2.FrontPen = screenpens[ SHINEPEN ];

	Pfeil1Gadg.GadgetRender = makearrowborder( Pfeil1Gadg.Width, Pfeil1Gadg.Height, TRUE, FALSE );
	Pfeil1Gadg.SelectRender = makearrowborder( Pfeil1Gadg.Width, Pfeil1Gadg.Height, TRUE, TRUE );
	Pfeil2Gadg.GadgetRender = makearrowborder( Pfeil2Gadg.Width, Pfeil2Gadg.Height, FALSE, FALSE );
	Pfeil2Gadg.SelectRender = makearrowborder( Pfeil2Gadg.Width, Pfeil2Gadg.Height, FALSE, TRUE );

	/* Init Info Gadget */
	realfontta_bold = realfontta;
	realfontta_bold.ta_Style |= FSF_BOLD;

	if( wbwindow )
	{
		infovec[2] = 8192;
		infoitext1.TopEdge = 1;
	}
	else
	{
		infovec[2] = screenxsize - 1;
		infoitext1.TopEdge = scr->BarHeight + 2;
	}
	infoborder1.TopEdge = topoffs - 3;
	infoborder2.TopEdge = infoborder1.TopEdge + 1;
	infoitext2.TopEdge = infoitext1.TopEdge + fontysize;

	screencols = ( scr->Width - 16 ) / fontxsize;
	//Printf( "screencols = %ld, scsr->Width = %ld, fontxize %ld\n", screencols, scr->Width, fontxsize );

/*	if( !wbwindow )
		qf_setplane( scr->RastPort.BitMap->Planes[0] + (scr->RastPort.BitMap->BytesPerRow*topoffs), scr->RastPort.BitMap->BytesPerRow);*/

	w = OpenWindow( &nw );
	if( !w )
		exiterror("kann Fenster nicht öffnen");

	if( !isv39 )
		rtSetWaitPointer( w );
	rp = w->RPort;

	recalcwindowsize();

	calcmaxpen();

	/*CloseFont( rp.Font );*/

	MYPROC->pr_WindowPtr=w;

	/* Create Term Menus */

#define ISFLG(x) ((prefs.flags&x)?2:0)
#define ISFLG2(x) ((prefs.flags2&x)?2:0)

	menurkey = LibCreatePool( MEMF_CLEAR, 4096, 2048 );

	menustrip = NULL;
	menux = 0;

	addmenu("Netcall");
	addmenuitem("Nächster Versuch ",(ULONG)"SPACE",MFRVAL(0x40));
	addmenuitem(0,0,0);
	addmenuitem("Abbruch",(ULONG)"ESC",MFRVAL(0x45));
	layoutmenus();
	netcallmenustrip = menustrip;
	menustrip=0;
	menux=0;

/* Shortcutliste

ABCDEFGHIJKLMNOPQRSTUVWXYZ ?+-., 8
XXXXXXXXXXXXXXXXX XXX XXX        X

*/

	addmenu("Terminal");
	addmenuitem("Bildschirm löschen",(ULONG)'L',0);
	addmenuitem(0,0,0);
	addmenuitem("Point-Serverbox anrufen",(ULONG)'C', 0 );
	addmenuitem("Telefonbuch...", (ULONG)'G', 0 );
	addmenuitem("User anrufen...",(ULONG)'I',0);
	addmenuitem("Beliebige Nummer anrufen...", (ULONG)'N', 0 ); 
	addmenuitem(0,0,0);
	addmenuitem("Auflegen",(ULONG)'H',0);
	addmenuitem(0,0,0);
	addmenuitem("Hilfe...",(ULONG)"HELP",0);
	addmenuitem(0,0,0);
	addmenuitem("Quit",(ULONG)'Q',0);

	addmenu( "Dateitransfer" );
	addmenuitem("Z-Modem-Upload...",(ULONG)'U',0);
	addmenuitem("Z-Modem-Download",(ULONG)'D',0);
	addmenuitem(0,0,0);
	addmenuitem("Z-Modem-8k",(ULONG)'8',1+ ISFLG2( MDF2_TERM_ZM8K ) );
	addmenuitem(0,0,0);
	addmenuitem("Upload-Liste...", (ULONG)'X', 0 );
	addmenuitem("Liste uploaden (Z-Modem)", (ULONG)'J', 0 );
	addmenuitem(0,0,0);
	addmenuitem("Hydra-Transfer...", (ULONG)'Y', 0 );

	addmenu( "Mitschnitt" );
	addmenuitem( "Mitschnitt aktiv?", (ULONG)'M', 1+ISFLG( MDF_TERM_LOG ) );
	addmenuitem( 0,0,0 );
	addmenuitem( "Mitschnitt-Bildschirm öffnen", (ULONG)'B', 0 );
	addmenuitem( 0,0,0 );
	addmenuitem( "Mitschnitt löschen", (ULONG)'E', 0 );
	addmenuitem( "Mitschnitt speichern...", (ULONG)'S', 0 );
	addmenuitem( "Mitschnitt als Nachricht speichern", (ULONG)'P', 0 );

	addmenu( "Einstellungen" );
	addmenuitem( "Auswählen...", (ULONG)'W', 0 );
	addmenuitem( "Modem...", (ULONG)'O', 0 );
	addmenuitem( "Terminal...", (ULONG)'T', 0 );
	addmenuitem( 0, 0, 0 );
	addmenuitem( "Funktionstasten...",(ULONG)'K',0);
	addmenuitem( "Dateitransfer...", (ULONG)'A', 0 );
	addmenuitem( 0, 0, 0 );
	addmenuitem( "Telefonbuch...", (ULONG)'F', 0 );

	layoutmenus();
	termmenustrip = menustrip;

	menustrip=0;
	menux=0;

	menumono = 1;

	addmenu("Mitschnitt-Bildschirm");
	addmenuitem( "Mitschnitt löschen", (ULONG)'E', 0 );
	addmenuitem( "Mitschnitt speichern...", (ULONG)'S', 0 );
	addmenuitem( "Mitschnitt als Nachricht speichern", (ULONG)'P', 0 );
	addmenuitem( 0,0,0 );
	addmenuitem( "Farben...", (ULONG)'F', 0 );
	addmenuitem( 0,0,0 );
	addmenuitem( "Hauptbildschirm nach vorne", (ULONG)'B', 0 );
	addmenuitem( 0,0,0 );
	addmenuitem( "Mitschnitt-Bildschirm schließen", (ULONG)'X', 0 );
	layoutmenus();
	protomenustrip=menustrip;
	menustrip=0;
	menux=0;

	menumono = 0;

/* Shortcutliste

ABCDEFGHIJKLMNOPQRSTUVWXYZ ?+-.,
XX   X  XXX  X XXXXXXX XXX XXXXX

*/
	addmenu("MD");
	addmenuitem("Netcall, komplett",(ULONG)'N',0);
	addmenuitem("Netcall, nur PMs holen...",0,0);
	addmenuitem("Netcall, nur Brettnachrichten holen...",0,0);
	addmenuitem("Netcall, nur Verschicken...",0,0);
	addmenuitem("Sortin...",(ULONG)'*',0);
	addmenuitem(0,0,0);
	addmenuitem("Terminal...",(ULONG)'T',0);
	addmenuitem(0,0,0);
	addmenuitem("Info...",(ULONG)'?',0);
	addmenuitem("Hilfe...",(ULONG)"HELP",MFRVAL(0x5f));
	addmenuitem(0,0,0);
	addmenuitem( "Wartestellung...", (ULONG)'I', 0 );
	addmenuitem( "Public-Screen auswählen...",(ULONG)'Y',0 );
	addmenuitem( 0, 0, 0 );
	addmenuitem("Quit",(ULONG)'Q',0);

	addmenu("Bretter");
	addmenuitem("Wählen",(ULONG)"ENTER",MFRVAL(0x44));
	addmenuitem("Markieren",(ULONG)"SPACE",MFRVAL(0x40));
	addmenuitem("Alle demarkieren",(ULONG)"~",MFRVAL(0));
	addmenuitem("Nach Namen markieren",(ULONG)"m", MFRVAL( 0x37 ) );
	addmenuitem("Alle markieren",(ULONG)"M", MFRVAL( 0x37 ) | MFRSHIFT );
	addmenuitem(0,0,0);
	addmenuitem("nächste neue Nachricht",(ULONG)"n",MFRVAL(0x36));
	addmenuitem("Nachricht schreiben...",(ULONG)"e",MFRVAL(0x12));
	addmenuitem( "Brett", 0, MFRINITSUB );
		addmenuitem("Parameter...",(ULONG)"p",MFRVAL(0x19));
		addmenuitem("Neues Brett...",(ULONG)"N",MFRVAL(0x36)|MFRSHIFT);
		addmenuitem("Neues PM-Brett...",(ULONG)"P",MFRVAL(0x19)|MFRSHIFT);
		addmenuitem("Inhalt Aufräumen...",(ULONG)"a",MFRVAL(0x20));
		addmenuitem("Inhalt komplett löschen...",(ULONG)"DEL",MFRVAL(0x46));
		addmenuitem("Brett löschen",(ULONG)"*DEL",MFRVAL(0x46)|MFRSHIFT);
		addmenuitem("Brettindex wiederherstellen...", (ULONG)"O", MFRVAL(0x18) | MFRSHIFT );
	addendsub();
	addmenuitem(0,0,0);
	addmenuitem( "Alles aufräumen...",(ULONG)"A",MFRVAL(0x20)|MFRSHIFT);
	addmenuitem( "Reorganisation...", (ULONG)"I", MFRVAL( 0x17 ) | MFRSHIFT );
	addmenuitem( "Nur Killfile aufräumen...", (ULONG)"k", MFRVAL( 0x27 ) ); 
	addmenuitem( "Alle Nachrichten auf alt...",(ULONG)"i",MFRVAL( 0x17 ) );
	addmenuitem( "Datenbank-Status...",(ULONG)"s", MFRVAL( 0x21 ) );

	addmenu("Nachrichten");
	addmenuitem("Lesen",(ULONG)"ENTER",MFRVAL(0x44));
	addmenuitem("Markieren",(ULONG)"SPACE",MFRVAL(0x40));
	addmenuitem("Neue Nachricht...",(ULONG)"e",MFRVAL(0x12));
	addmenuitem( "Antwort", 0, MFRINITSUB );
		addmenuitem("Private Antwort...",(ULONG)"p",MFRVAL(0x19));
		addmenuitem("Private Antwort/Zitieren...",(ULONG)"P",MFRVAL(0x19)|MFRSHIFT);
		addmenuitem("Öffentliche Antwort...",(ULONG)"a",MFRVAL(0x20));
		addmenuitem("Öffentliche Ant./Zitieren...",(ULONG)"A",MFRVAL(0x20)|MFRSHIFT);
	addendsub();
	addmenuitem("Weiterleiten...",(ULONG)"w",MFRVAL(0x11));
	addmenuitem("Erneut verschicken...",(ULONG)"W",MFRVAL(0x11)|MFRSHIFT);
	addmenuitem("Archivieren",(ULONG)"s",MFRVAL(0x21));
	addmenuitem( "Auslagern", 0, MFRINITSUB );
		addmenuitem("Auslagern...",(ULONG)"x",MFRVAL(0x32));
		addmenuitem("Auslagern mit Header...",(ULONG)"X",MFRVAL(0x32)|MFRSHIFT);
		addmenuitem("Auslagern/UUDecode",(ULONG)"u",MFRVAL(0x16));
	addendsub();
	addmenuitem("Drucken", (ULONG)"d", MFRVAL( 0x22 ) );
	addmenuitem("Editieren...",(ULONG)"E",MFRVAL(0x12)|MFRSHIFT);
	addmenuitem("Extern anzeigen",(ULONG)"v",MFRVAL(0x34));
	addmenuitem("Kopieren...", (LONG)"k", MFRVAL( 0x27 ) );
	addmenuitem(0,0,0);
	addmenuitem("nächste neue Nachricht",(ULONG)"n",MFRVAL(0x36));
	/*addmenuitem("nächste Antwort",(ULONG)"->",MFRVAL(0x4e));
	addmenuitem("vorherige Antwort",(ULONG)"<-",MFRVAL(0x4f));
	addmenuitem("erster Bezug",(ULONG)"*->",MFRVAL(0x4e)|MFRSHIFT);
	addmenuitem("Bezugsnachricht",(ULONG)"*<-",MFRVAL(0x4f)|MFRSHIFT);*/
	addmenuitem(0,0,0);
	addmenuitem("Thread killen...",(ULONG)"K",MFRVAL(0x27)|MFRSHIFT);
	addmenuitem("User filtern...",(ULONG)"U",MFRVAL(0x16)|MFRSHIFT);
	addmenuitem(0,0,0);
	addmenuitem("PGP-Signatur prüfen",(ULONG)"$",MFRVAL(0x04)|MFRSHIFT);
	addmenuitem("Absender speichern",(ULONG)"S",MFRVAL(0x21)|MFRSHIFT);
	addmenuitem(0,0,0);
	escswitchmenu = currentitem;
	addmenuitem("zurück zur Brettauswahl",(ULONG)"ESC",MFRVAL(0x45));
	escswitchmenu1 = currentitem;
	addmenuitem("zurück/NEU-Status löschen",(ULONG)"*ESC",MFRVAL(0x45)|MFRSHIFT);
	/*itemy -= 20;*/
	addmenuitem("zurück zur Brettauswahl",(ULONG)"*ESC",MFRVAL(0x45)|MFRSHIFT);
	escswitchmenu2 = currentitem;
	addmenuitem("zurück/NEU-Status löschen",(ULONG)"ESC",MFRVAL(0x45));

	addmenu("N-][");
	addmenuitem("Thread falten",(ULONG)"f",MFRVAL(0x23));
	addmenuitem("Ganzen Thread falten",(ULONG)"F",MFRVAL(0x23)|MFRSHIFT);
	addmenuitem("Alle Threads falten",(ULONG)"t",MFRVAL(0x14));
	addmenuitem("Alle Threads entfalten",(ULONG)"T",MFRVAL(0x14)|MFRSHIFT);
	addmenuitem(0,0,0);
	addmenuitem("Alle markieren",(ULONG)"M",MFRVAL(0x37)|MFRSHIFT);
	addmenuitem("Alle Neuen markieren",(ULONG)"N",MFRVAL(0x36)|MFRSHIFT);
	addmenuitem("Alle Ungelesenen markieren",(ULONG)"G",MFRVAL(0x24)|MFRSHIFT);
	addmenuitem("nach Muster markieren...",(ULONG)"m",MFRVAL(0x37));
	addmenuitem("Markierungen wiederherstellen...",(ULONG)"o",MFRVAL(0x18));
	addmenuitem(0,0,0);
	addmenuitem("Markierungen invertieren",(ULONG)"i",MFRVAL(0x17));
	addmenuitem("Alle demarkieren",(ULONG)"~",MFRVAL(0));
	addmenuitem(0,0,0);
	addmenuitem( "Darstellung", 0, MFRINITSUB );
		addmenuitem("Realnamen anzeigen?",(ULONG)'1',1+((prefs.flags&MDF_SHOWREAL)?2:0));
		addmenuitem("Alle Header anzeigen?",(ULONG)'2',1+((prefs.flags&MDF_SHOWALL)?2:0));
		addmenuitem("Nach Datum sortieren?",(ULONG)'3', 1 + ( ( prefs.flags & MDF_SORTDATE ) ? 2 : 0 ) );
		addmenuitem("'Re:' filtern?", (ULONG)'4', 1 + ( ( prefs.flags & MDF_FILTERRE ) ? 2 : 0 ) );
		addmenuitem("Schriftstile auswerten?", (ULONG)'5', 1 + ( ( prefs.flags & MDF_NOREADERSTYLES ) ? 0 : 2 ) );
		/*addmenuitem("Gelöschte Nachrichten anzeigen?", (ULONG)'5', 1 + ( ( prefs.flags & MDF_HIDEDEL ) ? 0 : 2 ) );*/
	addendsub();

	addmenuitem(0,0,0);
	addmenuitem("Ungelesen",(ULONG)"g",MFRVAL(0x24));
	addmenuitem("Gelesen",(ULONG)"l",MFRVAL(0x28));
	addmenuitem("Halten",(ULONG)"h",MFRVAL(0x25));
	addmenuitem("Löschen",(ULONG)"DEL",MFRVAL(0x46));
	addmenuitem("Wiedervorlage",(ULONG)"!",MFRVAL(0x1)|MFRSHIFT);
	addmenuitem(0,0,0);
	addmenuitem("Markierter Text ins Clipboard",(ULONG)'C',0);

	addmenu( "MAPS" );
	addmenuitem( "Bretter bestellen...",(ULONG)'+',0);
	addmenuitem( "Bretter abbestellen...",(ULONG)'-',0);
	addmenuitem( "Brettliste anfordern...",0,0);
	addmenuitem( "Hilfe anfordern",0,0);
	addmenuitem( 0, 0, 0 );
	addmenuitem( "PMs in Box löschen",0,0);
	addmenuitem( 0, 0, 0 );
	addmenuitem( "Sonstige Nachricht...",0,0);
	addmenuitem( 0, 0, 0 );
	addmenuitem("MicroDot-Mailingliste...",0,0);
	addmenuitem("Bugmeldung verschicken...",0,0);
	if( !registerinfo.serie )
		addmenuitem("Registrieren...",(ULONG)'R',0);

	addmenu("Prefs");

	addmenuitem( "Sprachen...", (ULONG)'L', 0 );
		/*addmenuitem( "Öffentlicher Origin...",0,0);
		addmenuitem( "Privater Origin...",0,0);
		addmenuitem( "Öffentlicher Quoteheader...",0,0);
		addmenuitem( "Privater Quoteheader...",0,0);
		addmenuitem( "Cookies...", 0, 0 );
	addendsub();*/
	addmenuitem(0,0,0);
	//addmenuitem( "Point", 			0, MFRINITSUB );
		addmenuitem( "Point...",	0, 0 );
		addmenuitem( "Modem...", 		0, 0 );
		addmenuitem( "Sysop-Modus...", 	0, 0 );
		addmenuitem( "Maps...", 		0, 0 );
	//addendsub();

	addmenuitem( "Netz...",			0, 0 );
	addmenuitem( "Userliste...", (ULONG)'U',0);
	addmenuitem( "Userfilterliste...",(ULONG)'K',0);

	addmenuitem( 0, 0, 0 );

	//addmenuitem( "Oberfläche", 0, MFRINITSUB );
		addmenuitem( "Externe Programme/Pfade...", (ULONG)'X', 0 );
		addmenuitem("Bildschirm...",(ULONG)'S',0);
		addmenuitem( "Farben...", (ULONG)'F', 0 );
		addmenuitem( "Bedienung I...", (ULONG)'B', 0 );
		addmenuitem( "Bedienung II...", (ULONG)'J', 0 );
	//addendsub();

	addmenuitem( 0, 0, 0 );
	addmenuitem( "Passwort aktiv", (ULONG)'P', 1 + ( ( prefs.flags & MDF_PASSWORD ) ? 2 : 0 ) );
	addmenuitem( "Passwort ändern...", 0, 0 );

	addmenu( "PGP" );
	addmenuitem( "Voreinstellungen...", 0, 0 );
	addmenuitem( "`Pass Phrase' setzen...",	 (ULONG)'Z', 0 );
	addmenuitem( "`Pass Phrase'/Trust-Werte ändern...", 0, 0 );
	addmenuitem( "Eigenen Key neu einlesen...", 0, 0 );
	addmenuitem(0,0,0);
	addmenuitem( "Eingegangene Keys verwalten...", (ULONG)'V', 0 );
	addmenuitem( "Keyring anzeigen...", (ULONG)'.', 0 );
	addmenuitem( "Keyring anzeigen (ausführlich)", (ULONG)',', 0 );
	addmenuitem( "Keyring-Konsistenz prüfen...", 0, 0 );

	if( isv37 && RexxSysBase )
	{
		addmenu("Rexx");
		addmenuitem( "Kommandoshell...", ( ULONG )'A', 0 );
		addmenuitem(0,0,0);
		if( IsListEmpty( &rexxl1 ) )
			addmenuitem( "Allgemeine Makros", 0, 0 );
		else
		{
			addmenuitem( "Allgemeine Makros", 0, MFRINITSUB );
			rexxlist2menu( &rexxl1, 0 );
			addendsub();
		}
		if( IsListEmpty( &rexxl2 ) )
			addmenuitem( "Brett-Makros", 0, 0 );
		else
		{
			addmenuitem( "Brett-Makros", 0, MFRINITSUB );
			rexxlist2menu( &rexxl2, 5 );
			addendsub();
		}
		if( IsListEmpty( &rexxl3 ) )
			addmenuitem( "Nachrichten-Makros", 0, 0 );
		else
		{
			addmenuitem( "Nachrichten-Makros", 0, MFRINITSUB );
			rexxlist2menu( &rexxl3, 5 );
			addendsub();
		}
	}

	layoutmenus();

	escswitchmenu1->NextItem->NextItem = NULL;

	escswitchmenu2->TopEdge = escswitchmenu1->TopEdge;
	escswitchmenu2->NextItem->TopEdge = escswitchmenu1->NextItem->TopEdge;

	setmenuescflag();

	rinfo = rtAllocRequest( RT_REQINFO, TAG_DONE );
	if( !rinfo )
		exiterror( "reqtools-fehler" );

	rinfo->ReqPos		= prefs.reqpos;
	rinfo->LockWindow	= TRUE;
	rinfo->ShareIDCMP	= FALSE;
	rinfo->ReqTitle		= "MicroDot-Request";

	/* Disable Menus */
	if( !wbwindow )
	{
		OffMenu( w, SHIFTMENU( 0 ) | SHIFTITEM( 9 ) );
	}
	

	if( !isv37 )
		OffMenu( w, SHIFTMENU( 0 ) | SHIFTITEM( 8 ) );

	OffMenu( w, FULLMENUNUM( 3, 22, NOSUB ) );

	if( scr->Height < 256 || scr->Width < 640 )
	{
		askreq(
			"MicroDot benötigt einen Bildschirm\nmit einer Größe von mindestens\n640 x 256 Pixeln.",
			"Abbruch"
		);
		exit( 10 );
	}

	settitletxt();
}

void setmenuescflag( void )
{
	ClearMenuStrip( w );
	if( prefs.flags2 & MDF2_ESCCLRNEW )
		escswitchmenu->NextItem = escswitchmenu2;
	else
		escswitchmenu->NextItem = escswitchmenu1;

	SetMenuStrip( w, menustrip );
}


#define MKF(x,y) ((x)<<6|(y))
#define GKF(x) ((x)>>6)

void doregister(void)
{
	static ULONG keyfilter[] = {
		MKF( 0x177, 3 ),	// Raubkopie
		MKF( 0x4, 7 ),		// Teuber
		MKF( 0x1, 5 ),		// Raubkopie
		MKF( 0x38b, 17 ),	// Raubkopie
		MKF( 0x114, 19 ),	// Raubkopie
		//MKF( 0x4eaf, 16 ),	// Raubkopie
		0
	};
	ULONG *kfp = keyfilter;

	keyseglist = LoadSeg( "MicroDot.KEY" );
	if( keyseglist )
	{
		ULONG v = 0x49814122;

		registerinfo.zero = MDUPDVER;
		callreg( keyseglist, &registerinfo );

		if( registerinfo.zero )
		{
			prefs.key_violation = 78;
			registerinfo.zero = 0;
		}

		registerinfo.func1( &v );
		//Printf( "v = %lx\n", v );
		if( v != 0x95819dd0 )
		{
			keyseglist = NULL;
			memset( &registerinfo, 0, sizeof( registerinfo ));
			prefs.key_violation = 78;
		}
	}

	//Printf( "seg = %lx, serie %ld, zero = %ld, txt = %s\n", keyseglist, registerinfo.serie, registerinfo.zero, registerinfo.registriert_txt );

	if( registerinfo.serie && !registerinfo.zero )
	{
		while( *kfp )
		{
			//Printf( "cmp: %ld\n", GKF( *kfp ) );
			if( GKF( *kfp ) == registerinfo.serie )
			{
				keyseglist = NULL;
				memset( &registerinfo, 0, sizeof( registerinfo ));
				prefs.key_violation = 78;
				break;
			}
			kfp++;
		}
		//registerinfo.zero = 0;
	}
}


static void initfr(void)
{
	int c;

	for( c = 0; c < 7; c++ )
		fr[c] = rtAllocRequest( RT_FILEREQ, NULL );

	rtChangeReqAttr( fr[ FR_EXCLUDE ], RTFI_Dir, prefs.txtex_pfad, TAG_DONE );
	rtChangeReqAttr( fr[ FR_EXCLUDE_BIN ], RTFI_Dir, prefs.binex_pfad, TAG_DONE );
	rtChangeReqAttr( fr[ FR_TERMUPLOAD], RTFI_Dir, prefs.term_uploadpath, TAG_DONE );
}

/* Diesmal mit BltTemplate() */

static __aligned struct RastPort ttrp1, ttrp2;
static __aligned struct BitMap ttbitmapstatic;
static __aligned struct BitMap *ttbitmap;
static ULONG ttx, ttbmsize;

static int fontbrushxp[ 7 ];
static int *linestarts;

static void initlinestarts( void )
{
	int c;

	if( !linestarts )
		linestarts = LibAllocPooled( miscmempool, 512 * sizeof( int ) );

	for( c = 0; c < 512; c++ )
		linestarts[ c ] = ( c * fontysize ) + topoffs;
}

#define LS(l) linestarts[l]

static void inittmptext( void )
{
	if( wbwindow )
		ttx = scr->Width;
	else
		ttx = screencols * fontxsize;

	/* Initialize TempText BitMap */

	if( isv39 )
	{
		ttbitmap = AllocBitMap( ttx, fontysize, 1, BMF_DISPLAYABLE, NULL );
		ttbmsize = ttbitmap->BytesPerRow * fontysize;
	}
	else
	{
		ttbitmap = &ttbitmapstatic;
		InitBitMap( &ttbitmapstatic, 1, ttx, fontysize );
		ttbmsize = RASSIZE( ttx, fontysize );
		ttbitmap->Planes[ 0 ] = allocchipmem( ttbmsize );
	}

	InitRastPort( &ttrp1 );
	ttrp1.BitMap = ttbitmap;
	/*ttrp.Mask = 1;*/

	SetFont( &ttrp1, listfont );
	sabd( &ttrp1, 1, 0, JAM2 );

	ttrp2 = ttrp1;
	SetSoftStyle( &ttrp2, FSF_BOLD, FSF_BOLD );	
}

void qf_inv( int line, int startcol, int endcol )
{
	endcol = min( endcol, screencols - 1 );
	ClipBlit(
		rp, startcol * fontxsize, LS( line ),
		rp, startcol * fontxsize, LS( line ),

		( endcol - startcol + 1 ) * fontxsize,
		fontysize,

		0x50
	);
}

void qf_ws( int line, int pen, UBYTE *txt )
{
	UBYTE cpy[ 512 ];
	UBYTE *p;
	int therewherestrangechars = 0;
	int c, d;
	struct RastPort *ttrp;
	int xp;

	/* Fill TempRast */
	BltClear( ttbitmap->Planes[ 0 ], ttbmsize, 0 );
	ttrp = ( prefs.pens[ pen + 2 ] ) ? &ttrp2 : &ttrp1;
	Move( ttrp, 0, listfont->tf_Baseline );

	cpy[ screencols ] = 0;
	strncpy( cpy, txt, screencols );

	/* Alle <7 durch Blanks ersetzen */
	p = cpy;
	while( *p )
	{
		if( *p < 8 )
		{
			therewherestrangechars++;
			*p = 32;
		}
		p++;
	}
	Text( ttrp, cpy, strlen( cpy ) );

	/* Sonderzeichen blitten */
	for( xp = 0, c = 0; therewherestrangechars; c++, xp += fontxsize )
	{
		d = *txt++;
		if( d > 7 )
			continue;

		therewherestrangechars--;

		BltBitMap( &fontbrushBitMap, fontbrushxp[ d - 1 ], 0,
		   ttbitmap, xp, 0,
		   fontxsize, fontysize, 
		   0xc0, 1, NULL
		);
	}

	sabd( rp, prefs.pens[ pen ], prefs.pens[ pen + 1 ], JAM2 );
	BltTemplate( ttbitmap->Planes[ 0 ], 0, ttbitmap->BytesPerRow,
		rp, 0, LS( line ),
		ttx, fontysize
	);
		
}

void qf_clr( int line )
{
	int ys = LS( line );

	SetAPen( rp, prefs.pens[ PEN_READ + 1 ] );
	RectFill( rp,
		0, ys,
		screenxsize - 17, ys + fontysize - 1
	);
}

void qf_wt( int line, struct dnode *n )
{
	int c, e;
	int mode = n->bold;
	int len = n->len, slen;
	int cs;
	int fp, bp, hb;

	if( !n )
	{
		qf_clr( line );
		return;
	}

	switch( mode )
	{
		case 0:
			fp = prefs.pens[ PEN_READ ];
			bp = prefs.pens[ PEN_READ + 1 ];
			hb = prefs.pens[ PEN_READ + 2 ] ? FSF_BOLD : 0;			
			break;
		case 1:
			fp = prefs.quotepens[ 0 ];
			bp = prefs.pens[ PEN_QUOTE + 1 ];
			hb = prefs.pens[ PEN_QUOTE + 2 ] ? FSF_BOLD : 0;			
			break;
		case 2:
			fp = prefs.pens[ PEN_HEAD ];
			bp = prefs.pens[ PEN_HEAD + 1 ];
			hb = prefs.pens[ PEN_HEAD + 2 ] ? FSF_BOLD : 0;			
			break;
		default:
			fp = prefs.quotepens[ ( mode - 2 ) % 7 ];
			bp = prefs.pens[ PEN_QUOTE + 1 ];
			hb = prefs.pens[ PEN_QUOTE + 2 ] ? FSF_BOLD : 0;			
			break;
	}

	SetFont( rp, listfont );
	sabd( rp, fp, bp, JAM2 );
	Move( rp, 0, LS( line ) + listfont->tf_Baseline );

	if( mode == 2 || prefs.flags & MDF_NOREADERSTYLES )
	{
		SetSoftStyle( rp, hb, FSF_BOLD | FSF_ITALIC | FSF_UNDERLINED );
		Text( rp, n->txt, len );
	}
	else
	{
		// Nun printen
		for( c = 0; c < len; )
		{
			cs = n->sty[ c ];
			for( e = c + 1; ( e < len ) && ( n->sty[ e ] == cs ); e++ );
			slen = e - c;
			SetSoftStyle( rp, cs ^ hb, FSF_BOLD | FSF_UNDERLINED | FSF_ITALIC );
			Text( rp, &n->txt[ c ], slen );
			c += slen;
		}
	}
	if( len < screencols )
	{
		if( wbwindow )
		{
			ClearEOL( rp );
		}
		else
		{
			SetAPen( rp, bp );
			RectFill( rp,
				rp->cp_x, rp->cp_y - listfont->tf_Baseline,
				screenxsize - 17, rp->cp_y - listfont->tf_Baseline + listfont->tf_YSize - 1
			);
		}
	}
}

#define BAR(n,x,y,maxx,maxy) RectFill(&frp,(n*fontxsize)+(x),y,(n*fontxsize)+(maxx),maxy)

static void makefontbrush( void )
{
	struct RastPort frp;
	int bmx = fontxsize * 7, bmy = fontysize;
	int xh = ( fontxsize - 1 ) / 2, yh = ( bmy - 1 ) / 2;
	int c;

	for( c = 0; c < 7; c++ )
		fontbrushxp[ c ] = fontxsize * c;

	InitRastPort( &frp );
	frp.BitMap = &fontbrushBitMap;

	InitBitMap( &fontbrushBitMap, 1, bmx, bmy );
	fbbitmapmem = allocchipmem( ( (bmx + 31 ) / 8 ) * bmy );
	fontbrushBitMap.Planes[ 0 ] = fbbitmapmem;

	sabd( &frp, 1, 0, JAM1 );

	/* 1 */
	BAR( 0, xh, 0, xh+1, bmy-1 );
	BAR( 0, xh, yh, fontxsize-1, yh+1 );

	/* 2 */
	BAR( 1, xh, 0, xh+1, bmy-1 );

	/* 3 */
	BAR( 2, 0, yh, fontxsize-1, yh+1 );

	/* 4 */
	BAR( 3, xh, 0, xh+1, yh );
	BAR( 3, xh, yh, fontxsize-1, yh+1 );

	/* 5 */
	BAR( 4, xh+1, 0, xh+1, bmy-1 );

	/* 6 */
	BAR( 5, 0, yh, fontxsize-1, yh+1 );
	BAR( 5, xh, yh, xh+1, bmy-1 );

	/* 7 */
	BAR( 6, xh, yh, fontxsize-1, yh+1 );
	BAR( 6, xh, yh, xh+1, bmy-1 );

	// Ecken abrunden
	SetAPen( &frp, 0 );
	WritePixel( &frp, ( 3 * fontxsize ) + xh , yh + 1 );
	WritePixel( &frp, ( 6 * fontxsize ) + xh, yh );

	inittmptext();
}


static void loadfont(void)
{
	struct TextFont *scrfont;
	struct TextAttr gadta;

	scrfont=OpenDiskFont( &screenfontta );
	if( !scrfont )
	{
		top80.ta_Name = "topaz.font";
		top80.ta_YSize = 8;
	}
	else CloseFont( scrfont );

	memset( &gadta, 0, sizeof( gadta ) );
	gadta.ta_YSize = prefs.gadfontheight;
	gadta.ta_Name  = prefs.gadfontname;
	scrfont = OpenDiskFont( &gadta );
	if( scrfont )
		CloseFont( scrfont );

	listfont = OpenDiskFont( &realfontta );
	if( !listfont )
	{
		realfontta.ta_Name = "topaz.font";
		realfontta.ta_YSize = 8;
		menufontta_bold.ta_Name = "topaz.font";
		menufontta_bold.ta_YSize = 8;
		listfont = OpenFont( &realfontta );
	}
	fontxsize = listfont->tf_XSize;
	fontysize = listfont->tf_YSize;
	fontbaseline = listfont->tf_Baseline;
}

extern struct WBStartup *_WBenchMsg;
static void parsewbargs(void)
{
	struct WBArg *wba;
	struct DiskObject *dobj;
	BPTR oldlock;
	char *p;
	char *tt;
	/*static char confignamebuffer[ 64 ];*/

	wba = _WBenchMsg->sm_ArgList;

	/* Programmnamen im ersten Arg */
	progname = wba->wa_Name;
	if( _WBenchMsg->sm_NumArgs > 1 )
		wba++;

	/* Read Icon */
	oldlock	=	CurrentDir( wba->wa_Lock );
	dobj	=	isv37 ? GetDiskObjectNew( wba->wa_Name ) : GetDiskObject( wba->wa_Name );
	CurrentDir( oldlock );

	if( !dobj )
		return;

	/* Booleans */
	if( tt = FindToolType( dobj->do_ToolTypes, "NETCALL" ) )
	{
		startnetcall = TRUE;

		switch( tolower( *tt ) )
		{
			case 'p':
				startnetcallmode = 1;
				break;
			case 'n':
				startnetcallmode = 2;
				break;
			case 'h':
				startnetcallmode = 3;
				break;
		}
	}
	if( FindToolType( dobj->do_ToolTypes, "TERMINAL" ) )
		startterminal = TRUE;
	if( FindToolType( dobj->do_ToolTypes,"CRUNCH") )
		do_autocrunch = TRUE;
	if( FindToolType( dobj->do_ToolTypes,"REORG" ) )
		do_autoreorg = TRUE;
	if( FindToolType( dobj->do_ToolTypes,"NOREQ" ) )
		noreq = TRUE;
	if( FindToolType( dobj->do_ToolTypes, "TERM" ) )
		startterminal = TRUE;
	if( FindToolType( dobj->do_ToolTypes, "NETCALL_RESUME" ) )
		netcall_resume = TRUE;

	pubscreenname = FindToolType( dobj->do_ToolTypes, "PUBSCREEN" );
	startupscriptname = FindToolType( dobj->do_ToolTypes, "STARTUP" );

/*	p = FindToolType( dobj->do_ToolTypes, "CONFIG" );
	if( !p )
		p = FindToolType( dobj->do_ToolTypes, "SETTINGS" );
	if( p )
	{
		strncpy( confignamebuffer, p, 63 );
		currentprefsname = confignamebuffer;
	}*/

	resethandlerenabled = (int) FindToolType( dobj->do_ToolTypes, "RESETHANDLER" );

	allow_trace = ( int ) FindToolType( dobj->do_ToolTypes, "__ALLOWTRACE" );

	if( FindToolType( dobj->do_ToolTypes, "__INSTANT_RESET" ) )
		ColdReboot();

	p = FindToolType( dobj->do_ToolTypes, "DIR" );
	if( !p )
		p = FindToolType( dobj->do_ToolTypes, "DIRECTORY" );
	if( p )
		chdir( p );

	FreeDiskObject(dobj);

}

#define dosws(s) Write(Output(),s,strlen(s))

extern ULONG _CLICmdLen;
extern STRPTR _CLICmd;

#define TEMPLATE "NETCALL/S,NETCALLMODE=NCM/K,TERM=TERMINAL/S,CRUNCH/S,REORG/S,NOREQ/S,NETCALL_RESUME/S,DIR=DIRECTORY/K,STARTUP/K,RESETGUI/S,PUBSCREEN/K"

/*#define TEMP_HELP	"\nMicroDOT " MDVER " © 1993-1994 Oliver Wagner, All Rights Reserved\n" \
					"\n Mögliche Optionen:\n" \
				 	" NETCALL\t\tNetcall ausführen und beenden\n" \
					" TERM=TERMINAL\t\tIm Terminal-Modus starten\n" \
					" TERM=TERMINAL\t\tIm Terminal-Modus starten\n" \
					" NETCALL_RESUME\t\tAbgebrochene Netcalls sichern und fortsetzen\n" \
					" DIR=DIRECTORY\t\tVerzeichnis für Konfigurationsdateien (def. PROGDIR:)\n" \
					" RESETGUI\t\tZurücksetzen aller GUI-Parameter\n" \
					" PUBSCREEN\t\tName des Publicscreens, auf dem das MicroDot geöffnet werden soll\n" \
					"\n" \
					TEMPLATE
*/

#ifdef MDV20
static void parsecliargs( void )
#else
static void parsecliargs(int argc,char **argv)
#endif
{
	int c;
	char temp_help[ 1024 ];

	sprintf( temp_help, "MicroDOT %s © 1993-1999 Oliver Wagner, All Rights Reserved\n\n"
			" %s\n"
			" NETCALL\t\t%s\n"
			" NETCALLMODE\t\t%s\n"
			" TERM=TERMINAL\t\t%s\n"
			" CRUNCH\t\t\t%s\n"
			" REORG\t\t\t%s\n"
			" NOREQ\t\t\t%s\n"
			" NETCALL_RESUME\t\t%s\n"
			" DIR=DIRECTORY\t\t%s\n"
			" STARTUP\t\t%s\n"
			" RESETGUI\t\t%s\n"
			" RESETHANDLER\t\t%s\n"
			" PUBSCREEN\t\t%s\n\n"
			TEMPLATE,

			MDVER,

			"Mögliche Optionen:",
			"Netcall ausführen und beenden",
			"Netcallmodus für NETCALL (P, N, H)",
			"Terminal starten",
			"Datenbank aufräumen",
			"Datenbank reorganisieren",
			"Alle Requester unterdrücken",
			"Abgebrochene Netcalls sichern",
			"Verzeichnis für Konfigurationsdateien (def. PROGDIR:)",
			"Sofort auszuführendes ARexx-Script",
			"Zurücksetzen aller GUI-Parameter",
			"Keyboard-Resethandler aktivieren",
			"Name des Publicscreens, auf dem das MicroDot-Fenster geöffnet werden soll"
	);

#ifdef MDV20
	GetProgramName( prognamebuffer, 128 );
	progname = prognamebuffer;
#else
	progname = argv[ 0 ];
#endif

	if( isv37 )
	{
		struct args {
			ULONG netcall;
			char *netcallmode;
			ULONG terminal;
			ULONG do_crunch;
			ULONG do_reorg;
			ULONG noreq;
			ULONG netcall_resume;
			char  *dir;
			char *startup;
			ULONG resetgui;
			ULONG reset;
			char *pubscreen;
		} argbuffer;
		struct RDArgs *rda2;

		memset( &argbuffer, 0, sizeof( argbuffer ) );

		rda2 = AllocDosObjectTags( DOS_RDARGS, TAG_DONE );
		if( !rda2 )
		{
			PrintFault( IoErr(), progname );
			exit( 20 );
		}
/*		rda2->RDA_Source.CS_Buffer = _CLICmd;
		rda2->RDA_Source.CS_Length = _CLICmdLen;*/
		rda2->RDA_ExtHelp = temp_help;
	/*	rda2->RDA_Flags &= ~RDAF_NOPROMPT;
		rda2->RDA_Flags |= RDAF_STDIN;*/
		rda = ReadArgs( TEMPLATE, (LONG*) &argbuffer, rda2 );

		if( !rda )
		{
			PrintFault( IoErr(), progname );
			FreeDosObject( DOS_RDARGS, rda2 );
			exit( 10 );
		}

		startnetcall = argbuffer.netcall;
		if( startnetcall && argbuffer.netcallmode )
		{
			switch( tolower( *argbuffer.netcallmode ) )
			{
				case 'p':
					startnetcallmode = 1;
					break;
				case 'n':
					startnetcallmode = 2;
					break;
				case 'h':
					startnetcallmode = 3;
					break;
			}
		}
		startterminal = argbuffer.terminal;
		netcall_resume = argbuffer.netcall_resume;
		resetgui = argbuffer.resetgui;
		noreq = argbuffer.noreq;
		do_autocrunch = argbuffer.do_crunch;
		do_autoreorg = argbuffer.do_reorg;
		if( argbuffer.dir )
			chdir( argbuffer.dir );

		pubscreenname = argbuffer.pubscreen;
		resethandlerenabled = argbuffer.reset;
		startupscriptname = argbuffer.startup;

		return;
	}

#ifndef MDV20

	for(c=1; c<argc; c++)
	{
		if( !stricmp( argv[c], "?" ) )
		{
			Write( Output(), temp_help, strlen( temp_help ) );
//			dosws( TEMP_HELP );
			dosws( "\n\n" );
			exit( 0 );
		}

		if(!stricmp(argv[c],"NETCALL")) startnetcall = TRUE;
		else if(!stricmp(argv[c],"TERMINAL")) startterminal = TRUE;
		else if(!stricmp(argv[c],"TERM")) startterminal = TRUE;
		else if(!stricmp(argv[c],"NOREQ")) noreq = TRUE;
		else if(!stricmp(argv[c],"CRUNCH")) do_autocrunch = TRUE;
		else if(!stricmp(argv[c],"REORG")) do_autoreorg = TRUE;
		else if(!stricmp(argv[c],"RESETGUI")) resetgui = TRUE;
		else if(!stricmp(argv[c],"RESETHANDLER")) resethandlerenabled = TRUE;
		else if(!stricmp(argv[c],"STARTUP")) startupscriptname = argv[ ++c ];
		else if(!stricmp(argv[c],"NETCALL_RESUME")) netcall_resume = TRUE;
		else if(!stricmp(argv[c],"DIR") || !stricmp( argv[c], "DIRECTORY" ) )
			chdir( argv[ ++c ] );
		else if(!stricmp(argv[c],"SETTINGS") || !stricmp( argv[c], "CONFIG" ) )
		{
			currentprefsname = argv[ ++c ];
		}
		else
		{
			dosws(progname);
			dosws(": unbekanntes Schlüsselwort ");
			dosws(argv[c]);
			dosws("\n");
		}
	}

#endif

}

long timezone_offset, timezone_dst;

/* Eigene Zeitzone rausfinden */
void mytzset( void )
{
	char x[6];
	time_t t;

	/* Gucken wir nach der Localtime */

	__tzset();

	t = time( NULL );
	utunpk( t, x );

	/* Sommerzeit ? */
	timezone_dst = FALSE;


	if( ( x[1] == prefs.sz_fm && x[2] >= prefs.sz_fd ) ||
		x[1] > prefs.sz_fm )
			timezone_dst = TRUE;

	if( ( x[1] == prefs.wz_fm && x[2] >= prefs.wz_fd ) ||
		x[1] > prefs.wz_fm )
			timezone_dst = FALSE;

	/* Offset berechnen */
	if( timezone_dst )
		timezone_offset = prefs.sz_offs * 3600;
	else
		timezone_offset = prefs.wz_offs * 3600;

}

static void donervreq( void )
{
	int oldnoreq = noreq;
	int rc;
	int days = ( ( time( 0 ) - prefs.firstinstalltime ) + 86399 ) / 86400;
	int loops = days / 30;

	noreq = 0;

redo:
	rc = askreq(

	"Herzlich Willkommen zum Test von MicroDot!\n\n"
	"Sie dürfen diese Testversion von MicroDot für 30\n"
	"Tage unverbindlich ausprobieren. Wenn Sie MicroDot\n"
	"danach weiterbenutzen möchten, müssen Sie entweder\n"
	"die Lizenzgebühr in Höhe von DM 30,-- bezahlen\n"
	"oder aufhören, MicroDot zu verwenden.\n"
	"Wenn Sie MicroDot lizensieren, erhalten Sie eine\n"
	"persönliche Schlüsseldatei (MicroDot.KEY), die\n"
	"Sie als ordentlichen Besitzer der Lizenz ausweist.\n\n"
	"Falls Sie mit diesen Lizenzbedingungen nicht\n"
	"einverstanden sind, beenden Sie MicroDot umgehend!\n\n"
	"Dies ist der %ld. Tag Ihrer 30tägigen%s Testphase",

	"Registrieren|Hilfe|Beenden|Weitertesten",

	days, days > 30 ? " ;-)" : "."

	 );

	if( rc == 2 )
	{
		showguide( "menu_brett_4_10" );
		goto redo;
	}
	else if( rc == 3 )
	{
		exit( 0 );
	}
	else if( rc == 1 )
		doregisterform();

	if( loops > 0 )
	{
		loops--;
		goto redo;
	}

	noreq = oldnoreq;
}

void *allocchipmem( int size )
{
	return( LibAllocPooled( chipmempool, size ) );
}

void enablejanus2menus( void )
{
	int enable = ( prefs.mode == MDM_JANUS ) && ( prefs.flags2 & MDF2_JANUS2 );

	if( enable )
	{
		OnMenu( w, FULLMENUNUM( 0, 1, NOSUB ) );
		OnMenu( w, FULLMENUNUM( 0, 2, NOSUB ) );
		OnMenu( w, FULLMENUNUM( 0, 3, NOSUB ) );
	}
	else
	{
		OffMenu( w, FULLMENUNUM( 0, 1, NOSUB ) );
		OffMenu( w, FULLMENUNUM( 0, 2, NOSUB ) );
		OffMenu( w, FULLMENUNUM( 0, 3, NOSUB ) );
	}
}

void opengui( void )
{
	static int firstrun;
	struct Screen *wbscr;

	//Printf("enter opengui\n" );

	if( !isv37 )
	{
		prefs.flags2 |= MDF2_OWNSCREEN;
	}
	else
	{
		wbscr = LockPubScreen( NULL );

		if( wbscr )
		{
			if( wbscr->Height < 256 )
				prefs.flags2 |= MDF2_OWNSCREEN;
			UnlockPubScreen( NULL, wbscr );
		}
	}

	wbwindow = ! ( prefs.flags2 & MDF2_OWNSCREEN );

	/* Init Font */

	realfontta.ta_Name 			= prefs.fontname;
	realfontta.ta_YSize 		= prefs.fontheight;
	menufontta_bold.ta_Name  	= prefs.fontname;
	menufontta_bold.ta_YSize 	= prefs.fontheight;
	screenfontta.ta_Name 		= prefs.screenfontname;
	screenfontta.ta_YSize 		= prefs.screenfontheight;
	//Printf("before loadfont\n" );
	loadfont();
	//Printf("before openwindow\n" );
	openwindow();

	//Printf("before makefontbrush\n" );
	makefontbrush();
	if( !wbwindow )
		startclock();

	if( firstrun++ )
	{
//		Printf("before resetscroller\n" );
		resetscroller();
//		Printf("after resetscroller\n" );
		ClearPointer( w );
	}

	/* AddAppIcon */
	if( wbwindow && WorkbenchBase )
	{
		appwindowmp = CreateMsgPort();
		appwindow = AddAppWindow( 42, NULL, w, appwindowmp, TAG_DONE );

		if( !appwindow )
		{
			DeleteMsgPort( appwindowmp );
			appwindowmp = NULL;
		}
		else
		{
			appwindowsig = 1 << appwindowmp->mp_SigBit;
		}
	}

	enablejanus2menus();

}

void closegui( void )
{
	removescrollgads();
	closewindow();

	if( isv39 && ttbitmap )
	{
		FreeBitMap( ttbitmap );
		ttbitmap = NULL;
	}
}

#define PS_LV 1
#define PS_OK 2
#define PS_CANCEL 3

void selectpubscreen( void )
{
	static char namebuffer[ MAXPUBSCREENNAME + 1 ];
	struct Screen *pscreen = scr;
	struct ogwin *ogw;
	struct Window *iw;
	struct IntuiMessage *im;
	int Done = FALSE;
	int entry = -1, lastentry = -1;
	ULONG lastsecs = 0, lastmics = 0;
	struct List *psl;
	struct PubScreenNode *psn;

	ogw = ogreInitWindow( scr, 0, 0, "Public-Screen auswählen:" );
	ogreAddGroup( ogw, 0 | OGGP_EXPANDSTRING, OGFRAME_NONE, NULL );
	ogreAddList( ogw, 0, 0xff, NULL, PS_LV, 40, 10, 0, NULL );
	ogreLVInit( ogw, PS_LV );


	psl = LockPubScreenList();
	psn = ( struct PubScreenNode * ) psl->lh_Head;

	while( psn->psn_Node.ln_Succ )
	{
		if( !( psn->psn_Flags & PSNF_PRIVATE ) )
			ogreLVAddEntry( ogw, PS_LV, psn->psn_Node.ln_Name, ( psn->psn_Screen == scr ) ? 3 : 2, NULL );
		psn = ( struct PubScreenNode * ) psn->psn_Node.ln_Succ;
	}
	UnlockPubScreenList();

	ogreAddButton( ogw, 1 | OGB_ONENTER, 'o', "_OK", PS_OK );
	ogreAddHelp( ogw, 1 );
	ogreAddButton( ogw, 1 | OGB_ONESC, 'a', "_Abbruch", PS_CANCEL );

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

	while( !Done )
	{
		im = ogreWaitIM( ogw );
		if( im->Class == IDCMP_GADGETHELP)
			showguidenum( "pubscreenwin_gads", im->Code );
		else if( im->Class == IDCMP_GADGETUP )
		{
			switch( im->Code )
			{
				case PS_LV:
					entry = ogreValue( ogw, PS_LV );
					if( entry == lastentry && DoubleClick( lastsecs, lastmics, im->Seconds, im->Micros ) )
						Done = 2;
					lastsecs = im->Seconds;
					lastmics = im->Micros;
					lastentry = entry;
					break;

				case PS_OK:
					Done = 2;
					break;
				case PS_CANCEL:
					Done = 1;
					break;
			}
		}
	}

	if( Done == 2 )
	{
		struct ogrevn *vn = ogreLVGetEntry( ogw, PS_LV, ogreValue( ogw, PS_LV ) );

		if( vn )
		{
			pscreen = LockPubScreen( vn->txt );
			if( pscreen && pscreen != scr )
				strcpy( namebuffer, vn->txt );
			if( pscreen )
				UnlockPubScreen( NULL, pscreen );
		}
	}

	ogreExitWindow( ogw );

	if( Done == 2 && namebuffer[ 0 ] )
	{
		closegui();
		prefs.flags2 &= ~MDF2_OWNSCREEN;
		wbwindow = TRUE;
		pubscreenname = namebuffer;
		opengui();
		ScreenToFront( scr );
	}
}


#if 0
static void drawtitlebox( int x, int y, int xs, int ys )
{
	SetAPen( rp, screenpens[ SHINEPEN ] );
	Move( rp, x, y );
	Draw( rp, x + xs - 1, y );
	Move( rp, x, y + 1 );
	Draw( rp, x, y + ys - 1 );
	SetAPen( rp, screenpens[ SHADOWPEN ] );
	Draw( rp, x + xs - 1, y + ys - 1 );
	Draw( rp, x + xs - 1, y );

	SetAPen( rp, screenpens[ FILLPEN ] );
	RectFill( rp, x + 1, y + 1, x + xs - 2, y + ys - 2 );

}

static void drawtitlenonsense( void )
{
	int xpc, ypc;
	int xs, ys;
	struct RastPort rp2;
	struct BitMap bm;
	int c, d;

	ypc = rp->Font->tf_YSize;
	xpc = TextLength( rp, "MICRODOT", 8 );

	InitRastPort( &rp2 );
	InitBitMap( &bm, 1, xpc + 1, ypc + 2 );
	rp2.BitMap = &bm;
	bm.Planes[ 0 ] = AllocRaster( xpc + 1, ypc + 2 );

	sabd( &rp2, 1, 0, JAM1 );
	Move( &rp2, 0, rp2.Font->tf_Baseline );
	Text( &rp2, "MICRODOT", 8 );

	xs = ( screenxsize - 16 - 32 ) / xpc;
	ys = ( ( screenlines * fontysize ) - 16 ) / ( ypc - 1 );

	for( c = 0; c < xpc; c++ )
	{
		for( d = 0; d < ( ypc - 1 ); d++ )
		{
			if( ReadPixel( &rp2, c, d ) )
				drawtitlebox( ( c * xs ) + 16, ( d * ys ) + topoffs + 8, xs, ys );
		}
	}

	FreeRaster( bm.Planes[ 0 ], xpc + 1, ypc + 2 );

}
#endif

#if 0
static int findenforcer( void )
{
	struct CommandLineInterface *cli;
	struct Process *pr;
	int c;
	UBYTE *np;

	if( ! ( SysBase->AttnFlags & AFF_68030 ) )
		return( -1 );

	for( c = 1; c <= MaxCli(); c++ )
	{
		Forbid();
		pr = FindCliProc( c );
		if( pr )
		{
			cli = BADDR( pr->pr_CLI );
			if( cli && cli->cli_CommandName )
			{
				char buffer[ 256 ];
				memset( buffer, 0, 256 );
				np = BADDR( cli->cli_CommandName );
				strncpy( buffer, &np[ 1 ], np[ 0 ] );
				if( !stricmp( FilePart( buffer ), "enforcer" ) && ( pr->pr_Task.tc_Node.ln_Pri == 99 ) )
				{
					Permit();
					return( -1 );
				}
			}
		}
		Permit();
	}
	if( FindTask( "Enforcer" ) || FindTask( "enforcer" ) || FindTask( "ENFORCER" ) )
		return( -1 );
	return( 0 );
}
#endif

static int samelock( BPTR l1, BPTR l2 )
{
	if( isv37 )
	{
		return( SameLock( l1, l2 ) == LOCK_SAME );
	}
	if( ( ( !l1 ) && l2 ) || ( ( !l2 ) && l1 ) )
		return( 0 );
	if( !l1 && !l2 )
		return( 1 );

	{
		struct FileLock *fl1 = BADDR( l1 ), *fl2 = BADDR( l2 );

		return( ( fl1->fl_Volume == fl2->fl_Volume ) && ( fl2->fl_Key == fl1->fl_Key ) );
	}

}

static BPTR _oldcd;
CONSTRUCTOR_P(savecd,10000)
{
	_oldcd = CurrentDir( DupLock( MYPROC->pr_CurrentDir ) );
	return( 0 );
}

DESTRUCTOR_P(savecd,10000)
{
	if( _oldcd )
	{
		UnLock( CurrentDir( _oldcd ) );
	}
}


static int installsysnode( void )
{
	struct mdresource *mdr;
	//ULONG memflags = ( isv39 ) ? (MEMF_CLEAR|MEMF_PUBLIC|MEMF_REVERSE) : (MEMF_CLEAR|MEMF_PUBLIC);
	struct mdsysnode *scan;
	int found = 0;

	Forbid();
	mdr = OpenResource( MDRS_NAME );
	/* Not found; install it */
	if( !mdr )
	{
		mdr = AllocMem( sizeof( *mdr ), MEMF_CLEAR | MEMF_PUBLIC );
		if( !mdr )
		{
			Permit();
			return( TRUE );
		}
		strcpy( mdr->id, MDRS_ID );
		strcpy( mdr->name, MDRS_NAME );
		mdr->lib.lib_Version = 1;
		mdr->lib.lib_Revision = 8;
		mdr->lib.lib_Node.ln_Name = mdr->name;
		mdr->lib.lib_IdString = mdr->id;
		mdr->lib.lib_Node.ln_Pri = -128;
		mdr->lib.lib_Node.ln_Type = NT_RESOURCE;
		mdr->lib.lib_PosSize = sizeof( *mdr );
		InitSemaphore( &mdr->sem );
		NewList( ( struct List * ) &mdr->list );

		AddResource( mdr );
	}
	ObtainSemaphore( &mdr->sem );
	Permit();

	/* Gut, Resource gefunden und belegt */

	/* SysNode init */
	mymdsysnode.progdir = Lock( "", SHARED_LOCK );
	mymdsysnode.transferpath = Lock( prefs.transferdir, SHARED_LOCK );
	mymdsysnode.datapath = Lock( prefs.datadir, SHARED_LOCK );

	scan = ( struct mdsysnode * ) mdr->list.mlh_Head;

	while( scan->n.mln_Succ )
	{
		if( samelock( scan->datapath, mymdsysnode.datapath ) ||
			samelock( scan->transferpath, mymdsysnode.datapath ) ||
            samelock( scan->progdir, mymdsysnode.progdir ) )
		{
			found = TRUE;
			break;
		}

		scan = ( struct mdsysnode * ) scan->n.mln_Succ;
	}

	if( !found )
		AddTail( ( struct List * ) &mdr->list, &mymdsysnode );

	ReleaseSemaphore( &mdr->sem );

	return( found );
}

#ifdef MDV20
static struct IntuiText Text5 = {0xff,0xff, /* pen numbers */
                             0,         /* draw mode */
                             6,45,     /* starting offsets */
                             NULL,      /* text attribute pointer */
                             "die auch auf Ihrem System läuft.",
                             NULL };
static struct IntuiText Text4 = {0xff,0xff, /* pen numbers */
                             0,         /* draw mode */
                             6,36,     /* starting offsets */
                             NULL,      /* text attribute pointer */
                             "Bitte benutzen Sie die normale Version,",
                             &Text5 };
static struct IntuiText Text3 = {0xff,0xff, /* pen numbers */
                             0,         /* draw mode */
                             6,22,     /* starting offsets */
                             NULL,      /* text attribute pointer */
                             "AmigaOS 3.0 und einer 68020 CPU.",
                             &Text4 };

static struct IntuiText Text2 = {0xff,0xff, /* pen numbers */
                             0,         /* draw mode */
                             6,13,     /* starting offsets */
                             NULL,      /* text attribute pointer */
                             "ein Amiga-System mit mindestens",
                             &Text3 };

static struct IntuiText BodyText = {0xff,0xff,      /* pen numbers */
                             0,         /* draw mode */
                             6,4,       /* starting offsets */
                             NULL,      /* text attribute pointer */
                             "Die 020-Version von MicroDot benötigt",
                             &Text2 };

static struct IntuiText ResponseText = {0xff,0xff,  /* pen numbers */
                             0,         /* draw mode */
                             4,4,       /* starting offsets */
                             NULL,      /* text attribute pointer */
                             "Beenden",
                             NULL };
CONSTRUCTOR_P(testaga,1)
{
	if( ( SysBase->LibNode.lib_Version < 39 ) || ( ! ( SysBase->AttnFlags & AFF_68020 ) ) )
	{
		struct Library *IntuitionBase = OldOpenLibrary( "intuition.library" );

		if( IntuitionBase )
		{
			AutoRequest( NULL, &BodyText, NULL, &ResponseText, 0, 0, 426, 94 );
			CloseLibrary( IntuitionBase );
		}
		return( 20 );
	}
	return( 0 );
}
#endif

extern void removeaddwindow( void );

extern void initdays( void );

extern void checkvalid( void );
extern void reportvalid( void );

#ifdef MDV20
void  __stdargs _main( char *dummy )
#else
void main(int argc,char **argv)
#endif
{
	long c;

	/*PutStr( "entering MD\n\n" );
	Delay( 100 );*/

#ifndef MDV20
	//isv37 = SysBase->LibNode.lib_Version > 36;
	isv39 =	SysBase->LibNode.lib_Version > 38;
	if( isv39 )
		memf_no_expunge = MEMF_NO_EXPUNGE;
#endif

	checkvalid();

//	genconvtables();

#ifndef MDV20
	if( isv39 )
#pragma msg 147 ignore push
		sabd_func = (((LONG)GfxBase)-894);
#pragma msg 147 pop
	else
		sabd_func = sabd13;
#endif

	/* Shell-Startup */
	if( !_WBenchMsg )
#ifdef MDV20
		parsecliargs();
#else
		parsecliargs( argc, argv );
#endif
	else
		parsewbargs();

	if( !Output() )
	{
		resetcurrentoutput = TRUE;

		if( isv37 )
			SelectOutput( Open( "NIL:", MODE_NEWFILE ) );
		else
			MYPROC->pr_COS = Open( "NIL:", MODE_NEWFILE );
	}
	if( !Input() )
	{
		resetcurrentinput = TRUE;

		if( isv37 )
			SelectInput( Open( "NIL:", MODE_NEWFILE ) );
		else
			MYPROC->pr_CIS = Open( "NIL:", MODE_NEWFILE );
	}

	DataTypesBase = OldOpenLibrary( "datatypes.library" );
	GadToolsBase = OldOpenLibrary( "gadtools.library" );
	KeymapBase = OldOpenLibrary( "keymap.library" );
	WorkbenchBase = OldOpenLibrary( "workbench.library" );
	RexxSysBase = OldOpenLibrary( "rexxsyslib.library" );
	XpkBase = OldOpenLibrary( "xpkmaster.library" );
	WhatIsBase = OldOpenLibrary( "whatis.library" );

	/* Init Memory Pools */
	chipmempool = LibCreatePool( MEMF_CHIP | MEMF_CLEAR | MEMF_PUBLIC, 1024, 512 );
	miscmempool = LibCreatePool( MEMF_CLEAR | MEMF_PUBLIC, 4096, 512 );
	sortinbuffer = LibAllocPooled( miscmempool, 16384 );

	AddFont( &mdmicroFont );
/*	if( isv37 )
		ExtendFontTags( &mdmicroFont, TAG_DONE );*/
	OpenFont( &mdmicroTA );

	multiport = CreatePort( NULL, 0 );

	/* Init Console Base */
	confakereq.io_Message.mn_ReplyPort = multiport;
	OpenDevice( "console.device", CONU_LIBRARY, &confakereq, 0 );
	ConsoleDevice = confakereq.io_Device;
	confakereq.io_Data = &conkeymap;
	confakereq.io_Length = sizeof( conkeymap );
	confakereq.io_Command = CD_ASKDEFAULTKEYMAP;
	DoIO( &confakereq );
	CloseDevice( &confakereq );

	doregister();

	LocaleBase = OldOpenLibrary( "locale.library" );

#ifndef MDV20
	/* %ld-Test */
	if( LocaleBase )
	{
		char buffer[ 8 ];

		sprintf( buffer, "%lD", 42 );
		if( atoi( buffer ) != 42 )
		{
			CloseLibrary( LocaleBase );
			LocaleBase = NULL;
		}
	}
#else
	if( !LocaleBase )
	{
		void __autoopenfail( STRPTR );
		__autoopenfail( "locale.library" );
		exit( -1 );
	}
#endif

	localeinfo.li_LocaleBase = LocaleBase;
#if 0
	if( LocaleBase )
	{
		localeinfo.li_Catalog = OpenCatalog( NULL,
			"MicroDot.catalog",
			OC_BuiltInLanguage, "deutsch",
			TAG_DONE
		);
	}
#endif

	oldprwindowptr = MYPROC->pr_WindowPtr;

	if( !( ReqToolsBase = (struct ReqToolsBase *) OpenLibrary( "reqtools.library", 38 ) ) )
		exiterror("kann 'reqtools.library' v38+ nicht öffnen");

	ixc_init();

	onexit( cleanup );

	initbuffmem();
	addmemhandler();

	strcpy( prefs.fontname, "topaz.font" );
	prefs.fontheight = 8;

	strcpy( prefs.screenfontname, "topaz.font" );
	prefs.screenfontheight = 8;

	strcpy( prefs.gadfontname, "mdmicro.font" );
	prefs.gadfontheight = 8;

	loadprefs( currentprefsname );
	initdays();

	if( !isv37 )
	{
		strcpy( prefs.fontname, "topaz.font" );
		prefs.fontheight = 8;

		strcpy( prefs.screenfontname, "topaz.font" );
		prefs.screenfontheight = 8;

		strcpy( prefs.gadfontname, "mdmicro.font" );
		prefs.gadfontheight = 8;
	}
	
	mytzset();
	reportvalid();

	if( resetgui )
	{
		strcpy( prefs.fontname, "topaz.font" );
		prefs.fontheight = 8;

		strcpy( prefs.screenfontname, "topaz.font" );
		prefs.screenfontheight = 8;

		strcpy( prefs.gadfontname, "mdmicro.font" );
		prefs.gadfontheight = 8;

		prefs.flags2 &= ~MDF2_OWNSCREEN;
		prefs.usecustomcolors = 0;

		getwbcolors();
	}

	readrexxdir();

	opengui();
	removeaddwindow();

/*	drawtitlenonsense();*/

	initfr();

	inithomedir();

	if( prefs.flags2 & MDF2_NOPREFS )
		doprefsnewinit();

	loadbretter();

	sortbrettlist();
	settitletxt();

/*	prefs.flags &= ~MDF_PASSWORD;
	prefs.passwordcrc = 0;*/

	setuparexx();

/*	if( !findenforcer() )
	{
		exiterror( "Diese MicroDOT-Version läuft nur mit Enforcer!\n" );
	}*/


#if 0
	if( !registerinfo.serie )
	{
		exiterror( "Diese MicroDOT-Version (" MDVER ") ist nur für registrierte AnwenderInnen.\n");
		exit( 0 );
	}
#endif

	initkbresethandler();

	if( startterminal )
	{
		if( !wbwindow )
			lockwindow();
		doterminal();
		if( !wbwindow )
			unlockwindow();
		exit( 0 );
	}

	c = checkpath( prefs.datadir );
	if( c )
	{
		askreq("Fehler: Data-Verzeichnis\n%s\nläßt sich nicht anlegen (%ld)","Abbruch",prefs.datadir,c);
		exiterror("kann DATA-Verzeichnis nicht anlegen");
	}
	c = checkpath(prefs.transferdir);
	if( c )
	{
		askreq("Fehler: Transfer-Verzeichnis\n%s\nläßt sich nicht anlegen (%ld)","Abbruch",prefs.transferdir,c);
		exiterror("kann Transfer-Verzeichnis nicht anlegen");
	}

	if( installsysnode() ) 
	{
		prefs.flags2 |= MDF2_NOPREFS;
		askreq( "Es läuft bereits eine MicroDot-Instanz\nmit denselben Parametern und/oder der\ngleichen Datenbank!", "Beenden" );
		exit( 5 );
	}

	if( !isv37 )
		OffMenu( w, FULLMENUNUM( 0, 9, NOSUB ) );

	if( isv37 )
		pgp_init();

	if( !pgpavail )
	{
		OffMenu( w, FULLMENUNUM( 6, NOITEM, NOSUB ) );
		OffMenu( w, SHIFTMENU( 2 ) | SHIFTITEM( 20 ) | SHIFTSUB( NOSUB ) );
	}

	settitletxt();

	if( !registerinfo.serie )
		donervreq();

	addlogfile( "START MicroDot V" MDVER );

	/* Normaler Modus */
	execrexx( "Startup" );
	if( rexxhost && startupscriptname )
		SendRexxCommand( rexxhost, startupscriptname, NULL );

	if( do_autoreorg || do_autocrunch )
	{
		if( do_autocrunch )
			docrunch( ( struct mbrett*)-1 );

		if( do_autoreorg )
			doreorg2( FALSE );
		exit( 0 );
	}

	if( startnetcall )
	{
		if( !dospool() )
		{
			if(!donetcall( startnetcallmode ))
			{
				delspool();
				dosortin();
				sortbrettlist();
				exit( 0 );
			}
		}
		/* Netcall nicht geklappt */
		exit( 5 );
	}

	if( prefs.flags & MDF_PASSWORD )
		docheckpassword();

	/* Gibt es etwas zu autosortieren? */
	if( exists( "microdot.autosortin" ) )
	{
		loadmke();
		loaduk();
		sortinfile( "microdot.autosortin" );
		freemke();
		freeuk();
		DeleteFile( "microdot.autosortin" );
		sortbrettlist();
	}

	enablejanus2menus();

	for(;;)
	{
		dobretter();
		execrexx( "BoardExit" );
	}
}
