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

#include <libraries/amigaguide.h>
#include <clib/amigaguide_protos.h>
#include <pragmas/amigaguide_pragmas.h>
#include <proto/console.h>
#include <proto/locale.h>

#include <dos/dostags.h>
#include <dos/exall.h>

static int makefilelistexall( BPTR dirlock, char *pattern, char *buffer, int buffersize )
{
	struct ExAllControl *eac;
	char pp[ 256 ];
	struct ExAllData *ead;
	void *eadmem;
	int counter = 0;
	int cont, entrylen;
	int entries;

	ParsePatternNoCase( pattern, pp, 256 );
	eadmem = AllocVec( 4096, MEMF_CLEAR );
	if( !eadmem )
		return( 0 );

	eac = AllocDosObjectTags( DOS_EXALLCONTROL, TAG_DONE );
	if( !eac )
	{
		FreeVec( eadmem );
		return( 0 );
	}
	eac->eac_MatchString = pp;
	eac->eac_LastKey = 0;

	do
	{
		cont = ExAll( dirlock, eadmem, 4096, ED_TYPE, eac );
		ead = eadmem;

		entries = eac->eac_Entries;

		while( entries-- && ead )
		{
			/* Dir */
			if( ead->ed_Type < 0 )
			{
				entrylen = strlen( ead->ed_Name ) + 1;

				if( entrylen >= buffersize )
				{
					buffersize = 0;
					break;
				}

				/* Anfügen */
				strcpy( buffer, ead->ed_Name );
				buffer += entrylen;
				buffersize -= entrylen;
				counter++;
			}
			ead = ead->ed_Next;
		}
	} while( cont && buffersize );

	if( !buffersize && isv39 )
		ExAllEnd( dirlock, eadmem, 4096, ED_TYPE, eac );

	FreeVec( eadmem );
	FreeDosObject( DOS_EXALLCONTROL, eac );

	*buffer = 0;

	return( counter );
}

int makefilelist( char *dir, char *pattern, char *buffer, int buffersize )
{
	BPTR dirlock = Lock( dir, SHARED_LOCK );
	struct FileInfoBlock *fib;
	int counter = 0;
	int entrylen;

	if( !dirlock )
	{
		char buffer2[ 256 ];
		char *p;

		strcpy( buffer2, dir );
		p = strchr( buffer2, 0 ) - 1;
		if( buffer2[ 0 ] && ( *p == '/' ) )
			*p = 0;
		dirlock = Lock( buffer2, SHARED_LOCK );
		if( !dirlock )
			return( 0 );
	}

	if( isv37 )
	{
		counter =  makefilelistexall( dirlock, pattern, buffer, buffersize );
		UnLock( dirlock );
		return( counter );
	}

	fib = allocfib();
	if( !fib )
	{
		UnLock( dirlock );
		return( 0 );
	}

	if( Examine( dirlock, fib ) )
	{
		while( ExNext( dirlock, fib ) )
		{
			/* Verzeichnis? */
			if( fib->fib_DirEntryType > 0 )
				continue;

			/* Pattern match */
			if( !astcsma( fib->fib_FileName, pattern ) )
				continue;

			entrylen = strlen( fib->fib_FileName ) + 1;

			if( entrylen >= buffersize )
				break;

			/* Anfügen */
			strcpy( buffer, fib->fib_FileName );
			buffer += entrylen;
			buffersize -= entrylen;
			counter++;
		}
	}

	*buffer = 0;

	freefib( fib );
	UnLock( dirlock );

	return( counter );
}


BPTR OpenAppend( char *name )
{
	BPTR f;

	f = Open( name, MODE_OLDFILE );
	if( f )
	{
		Seek( f, 0, OFFSET_END );
		return( f );
	}
	f = Open( name, MODE_NEWFILE );
	return( f );
}

/* Prüft, ob File existiert */

int exists( char * filename )
{
	BPTR lock = Lock( filename, SHARED_LOCK );

	if( lock )
	{
		UnLock( lock );
		return( -1 );
	}
	else
		return( 0 );
}

BPTR OpenCon( char *cfg )
{
	static char buf[ 256 ];

	strcpy( buf, cfg );
	if( pubscreenname )
	{
		asprintf( buf, "/SCREEN%s", pubscreenname );
	}

	return( Open( buf, MODE_OLDFILE ) );
}


BPTR openconsole( char *title )
{
	char titmem[ 128 ];

	convertstring( prefs.console_window, titmem,
		't', title,
		0
	);

	return( OpenCon( titmem ) );
}


struct FileInfoBlock *allocfib( void )
{
	if( isv37 )
		return( AllocDosObject( DOS_FIB, TAG_DONE ) );
	else
		return( AllocMem( sizeof( struct FileInfoBlock ), MEMF_CLEAR | MEMF_PUBLIC ) );
}

void freefib( struct FileInfoBlock *fib )
{
	if( fib )
	{
		if( isv37 )
			FreeDosObject( DOS_FIB, fib );
		else
			FreeMem( fib, sizeof( *fib ) );
	}
}

void __stdargs convertstring( char *from, char *to, ULONG id, char *data, ... )
{
	ULONG *idp;
	char **datap;
	int ch;

	while( *from )
	{
		if( *from != '%' )
		{
			*to++ = *from++;
			continue;
		}
		from++;
		ch 		= *from++;
		idp 	= &id;
		datap 	= &data;
		while( *idp )
		{
			/* Replacement char gefunden */
			if( *idp == ch )
			{
				strcpy( to, *datap );
				to = strchr( to, 0 );
				break;
			}
			idp++; idp++;
			datap++; datap++;
		}
		/* Nicht gefunden, Zeichen 1:1 übernehmen */
		if( !*idp )
			*to++ = ch;
	}
	*to = 0;
}


void num2b64( long val, char *dest )
{
	int c;

	static char sextet[] =  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
         "abcdefghijklmnopqrstuvwxyz"
         "0123456789+$";

	for( c = 4; c >= 0; c-- )
	{
		dest[c] = sextet[ val % 64 ];
		val = val / 64;
	}
	dest[5] = 0;
}

int copyicon( char *from, char *to )
{
	struct DiskObject *obj;

	if( !from )
		return( -1 );

	if( isv37 )
	{
		obj = GetDiskObjectNew( from );
	}
	else
	{
		obj = GetDiskObject( from );
	}

	if( !obj )
		return( -1 );

	PutDiskObject( to, obj );
	FreeDiskObject( obj );

	return( 0 );
}


char *errorstring( int n )
{
	static char errorbuf[64];

	if( isv37 )
	{
		Fault( n, NULL, errorbuf, 64 );
		return( errorbuf );

	}

	return( "" );
}

int fileexistsreq( char *file )
{
	BPTR tl;
	int rc;

	tl = Lock( file, SHARED_LOCK );
	if( !tl )
		return( 1 );

	UnLock( tl );
	rc = askreq("Datei\n%s\nexistiert bereits!","Über_schreiben|Anhän_gen|Abbruch", file );

	return( rc );
}

void nofilereq( char *file, int rc )
{
	askreq("Datei\n%s\nläßt sich nicht öffnen (Fehler %ld)\n%s","Abbruch",file, rc, errorstring( rc ) );
}

static void *windowlock;
void lockwindow(void)
{
	if( !wbwindow )
		windowlock = rtLockWindow( w );
	else
	{
		rtSetWaitPointer( w );
		w->Flags |= WFLG_RMBTRAP;
	}
}
void unlockwindow(void)
{
	struct Message *m;

	if( !wbwindow )
	{
		rtUnlockWindow( w, windowlock );
	}
	else
	{
		while( ( m = GetMsg( w->UserPort ) ) )
			ReplyMsg( m );
		w->Flags &= ~WFLG_RMBTRAP;
		ClearPointer( w );
	}
}

extern struct Screen *scr;

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

void showguidenum( char *head, int n )
{
	if( n < 0 || n >= 65535 )
	{
		showguide( head );
	}
	else
	{
		char txt[64];
		sprintf( txt, "%s_%ld", head, n );
		showguide( txt );
	}
}

static AMIGAGUIDECONTEXT aga;
struct Library *AmigaGuideBase;

static char guidename[ 256 ];
#define TESTGUIDE(s) strcpy(guidename,s);if(exists(guidename))return(0);
#include <constructor.h>
CONSTRUCTOR_P(findguide,25000)
{
	TESTGUIDE("MicroDot.GUIDE");
	TESTGUIDE("HELP:MicroDot.GUIDE");
	TESTGUIDE("HELP:Deutsch/MicroDot.GUIDE");
	TESTGUIDE("HELP:GUIDE/MicroDot.GUIDE");
	TESTGUIDE("MicroDot.GUIDE");
	return( 0 );
}

void showguide( char *node )
{
	static char cmd[ 80 ];
	static char *ag_context[] = { "MAIN", 0 };

	//Printf( "showguide '%s'\n", node );

	if( !aga )
	{
		struct NewAmigaGuide nag;
		struct AmigaGuideMsg *agm;
		int ok = FALSE;

		pushhomedir();
		if( !AmigaGuideBase )
			AmigaGuideBase = OpenLibrary( "amigaguide.library", 34 );
		if( !AmigaGuideBase )
		{
			displaybeep();
			askreq( "Die 'amigaguide.library' V34 (oder höher)\nläßt sich nicht öffnen!", "Keine Hilfe verfügbar" );
			popdir();
			return;
		}

		if( !exists( guidename ) )
		{
			displaybeep();
			askreq( "Die Hilfsdatei 'MicroDot.Guide'\nläßt sich nicht öffnen!","Keine Hilfe verfügbar");
			popdir();
			return;
		}
		memset( &nag, 0, sizeof( nag ) );

		nag.nag_Lock   		= NULL;
		nag.nag_Name   		= guidename;
		nag.nag_Screen 		= scr;
		// nag.nag_Flags  		= HTF_CACHE_NODE;
		nag.nag_BaseName	= "MicroDot";
		nag.nag_ClientPort  = "MICRODOT_HELP";
		nag.nag_Context		= ag_context;
		// nag.nag_Node		= "MAIN";

		aga = OpenAmigaGuideAsyncA( &nag, TAG_DONE );
		if( !aga )
		{
			displaybeep();
			popdir();
			askreq( "Die Hilfsdatei 'microdot.guide'\nläßt sich nicht öffnen!","Keine Hilfe verfügbar");
			return;
		}

		SetAmigaGuideContext( aga, NULL, NULL );

		/* Active Tool-ID abwarten */
		while( !ok )
		{
			Wait( AmigaGuideSignal( aga ) );
			while( agm = GetAmigaGuideMsg( aga ) )
			{
				if( agm->agm_Type == ( ActiveToolID ) )
					ok = TRUE;
				ReplyAmigaGuideMsg( agm );
			}
		}

		popdir();
	}

	sprintf( cmd, "ALINK %s", node );
	SendAmigaGuideCmdA( aga, cmd, NULL );
}

void closeguide( void )
{
	if( aga )
	{
		struct AmigaGuideMsg *agm;

		while( agm = GetAmigaGuideMsg( aga ) )
			ReplyAmigaGuideMsg( agm );

		CloseAmigaGuide( aga );
		aga = NULL;
	}

	if( AmigaGuideBase )
	{
		CloseLibrary( AmigaGuideBase );
		AmigaGuideBase = NULL;
	}
}

void calleditor( char *file )
{
	char buff[128];
	long rc;
    char *p;

	p = strchr( prefs.editor, '%' );
	if( p && ( p[1]=='s' || p[1]=='S' ) )
	{
		sprintf( buff, prefs.editor, file, "", "", "", "", 0, 0, 0 );
	}
	else sprintf( buff, "%s %s", prefs.editor, file );

	/*lockwindow();*/
	if( !wbwindow && prefs.editor_wb )
		WBenchToFront();

	if( isv37 )
	{
		rc = SystemTags( buff, NP_StackSize, max( prefs.editor_stack, 4096 ), TAG_DONE );
	}
	else
	{
		rc = system( buff );
	}

	ScreenToFront( scr );

	/*unlockwindow();*/

	if(rc<0)
	{
		askreq("Fehler beim Editor-Aufruf:\n%s\n","Abbruch",buff);
		return;
	}
}

/* Prueft & baut Pfad auf 0 = ok, != IoErr */
long checkpath(char *path)
{
	char buff[256];
	char *p;
	BPTR lock;

	lock=Lock(path,SHARED_LOCK);
	if(lock) {
		UnLock(lock);
		return(0);
	}

	p=strchr(path,':');
	if(!p) p=path;

	while(*p) {
		strcpy(buff,path);
		while(*p&&*p!='/') p++;
		buff[p-path]=0; if(*p)p++;
		/*Printf("check:%s\n",buff);*/
		lock=Lock(buff,SHARED_LOCK);
		if(!lock) {
			lock=CreateDir(buff);
			if(!lock) return(IoErr());
		}
		UnLock(lock);
	}
	return(0);
}

void addpart(char *part,char *file)
{
	if(!file) return;
	if(*file=='/') file++;
	if(part[0] && part[strlen(part)-1]!=':' && part[strlen(part)-1]!='/') strcat(part,"/");
	strcat(part,file);

}

#define D_S(type,name) char a_##name[sizeof(type)+3]; \
                       type *name = (type *)((LONG)(a_##name+3) & ~3);
long getfilelen( char * file )
{
	BPTR lock;
	long size;
	D_S(struct FileInfoBlock,fib);

	lock = Lock( file, SHARED_LOCK );
	if( !lock )
		return( -1 );

	Examine( lock, fib );
	UnLock( lock );
	size = fib->fib_Size;

	return( size );
}

void makedospath(char *path)
{
	if(!path || !*path) return;
	if(path[strlen(path)-1]!='/' && path[strlen(path)-1]!=':') strcat(path,"/");
}

void makebrettname(char *name)
{
	char *p;

	if(!name || !name[0]) return;

	p = name;
	strupr( p );
	if( p[ 0 ] != '/' )
	{
		p[ 78 ] = 0;
		strins( p, "/" );
	}
	while((p=strchr(name,' ')))
		strcpy(p,&p[1]);
	p=strchr(name,'/');
	do
	{
		p++;
		if(*p=='/') strcpy(p,&p[1]);
		p=strchr(p,'/');
	} while(p);
}

void makebrettnamenoup(char *name)
{
	char *p;

	if(!name || !name[0]) return;

	p = name;
	if( p[ 0 ] != '/' )
	{
		p[ 78 ] = 0;
		strins( p, "/" );
	}
	while((p=strchr(name,' ')))
		strcpy(p,&p[1]);
	p=strchr(name,'/');
	do
	{
		p++;
		if(*p=='/') strcpy(p,&p[1]);
		p=strchr(p,'/');
	} while(p);
}

char *filepart(char *path)
{
	char *p=strchr(path,0);

	while(p>=path) {
		if(*p=='/'||*p==':') return(++p);
		p--;
	}
	return(path);
}

int copyfile(char *from,char *to)
{
	long len=getfilelen(from);
	BPTR f1,f2;
	void *buffer;
	long blen;
	int rc;

	if(len<0) return(IoErr());
	f1 = Open( from, MODE_OLDFILE );
	if(!f1) return(IoErr());
	f2 = Open( to, MODE_NEWFILE );
	if(!f2)
	{
		rc=IoErr();
		Close(f1);
		return(rc);
	}

	buffer = allocbuffmem( len, &blen );

	while(len>0)
	{
		rc=Read(f1,buffer,blen);
		if( rc < 1 )
			break;
		Write(f2,buffer,rc);
		len-=rc;
	}

	freebuffmem();
	Close(f1);
	Close(f2);

	return(0);
}

int movefile( char *from, char *to )
{
	int rc;

	DeleteFile( to );
	if( Rename( from, to ) )
		return( 0 );
	rc = IoErr();
	if( rc != ERROR_RENAME_ACROSS_DEVICES )
		return( rc );
	rc = copyfile( from, to );
	if( rc )
		return( rc );
	DeleteFile( from );
	return( 0 );
}

extern struct KeyMap conkeymap;
int getrawkeycode( char *string )
{
	int c;
	UBYTE cmp[4];
	UBYTE *dead;

	for( c = 0; c < 64; c++ )
	{

		/*if( ( conkeymap.km_LoKeyMapTypes[c] & KC_VANILLA ) != KC_VANILLA )
			continue;*/
		if( conkeymap.km_LoKeyMapTypes[c] & KCF_STRING )
			continue;

		if( conkeymap.km_LoKeyMapTypes[c] & KCF_DEAD )
		{
			memcpy( &dead, &conkeymap.km_LoKeyMap[c], 4 );

			if( dead[0] & DPF_MOD )
			{
				dead = &dead[ dead[1] ];

				if( dead[0] == string[0] )
				{
					return( c );
				}
			}
			if( dead[2] & DPF_MOD )
			{
				dead = &dead[ dead[3] ];

				if( dead[0] == string[0] )
				{
					return( c | 0x100);
				}
			}

			if( !dead[0] && dead[1] == string[0] )
			{
				return( c );
			}

			if( !dead[2] && dead[3] == string[0] )
			{
				return( c | 0x100 );
			}
		}
		else
		{
			memcpy( cmp, &conkeymap.km_LoKeyMap[c], 4 );
			if( cmp[3] == string[0] )
			{
				return( c );
			}
			if( cmp[2] == string[0] )
			{
				return( c | 0x100 );
			}
		}
	}

	return( 0 );
}

char *rawkeyconvert( struct IntuiMessage *im )
{
	struct InputEvent ie;
	static char buffer[16];

	memset( &ie, 0, sizeof( ie ) );
	buffer[0] = 0;

	ie.ie_Class = IECLASS_RAWKEY;
	ie.ie_Code = im->Code;
	ie.ie_Qualifier = im->Qualifier;

	RawKeyConvert( &ie, buffer, 16, NULL );

	return( buffer );
}

#if 0
int str2_7bit( UBYTE *string, UBYTE *dest )
{
	int count = 0;

	while( *string )
	{
		if( *string>126 )
		{
			switch( *string )
			{
				case (UBYTE)'ä':
					*dest++ = 'a';
					*dest++ = 'e';
					count += 2;
					break;
				case (UBYTE)'ö':
					*dest++ = 'o';
					*dest++ = 'e';
					count += 2;
					break;
				case (UBYTE)'ü':
					*dest++ = 'u';
					*dest++ = 'e';
					count += 2;
					break;
				case (UBYTE)'Ä':
					*dest++ = 'A';
					*dest++ = 'e';
					count += 2;
					break;
				case (UBYTE)'Ö':
					*dest++ = 'O';
					*dest++ = 'e';
					count += 2;
					break;
				case (UBYTE)'Ü':
					*dest++ = 'U';
					*dest++ = 'e';
					count += 2;
					break;
				case (UBYTE)'ß':
					*dest++ = 's';
					*dest++ = 'z';
					count += 2;
					break;
				case (UBYTE)'»':
					*dest++ = '>';
					count++;
					break;
				case (UBYTE)'«':
					*dest++ = '<';
					count++;
					break;
				default:
					sprintf( dest, "\\%02lx", *((UBYTE*)string) );
					dest += 3;
					count += 3;
					break;
			}
			string++;
		}
		else
		{
			*dest++ = *string++;
			count++;
		}
	}
	*dest = 0;
	return( count );
}
#endif

/* Wort ausschneiden (bei word==-1 das letzte) */

void sbreakword(char *to,char *from,int word,int maxlen)
{
	int count;
	char *p;

	/* Anzahl Wörter feststellen */
	for(count=0,p=from; *p; p++) {
		if(isspace(*p)) count++;
	}
	/* count enthält anzahl wörter -1 */
	if(word<0) word=count;

	/* word'te wort finden */
	for(p=from; word; word--) {
		while(*p && !isspace(*p)) p++;
	}
	if(isspace(*p)) p++;

	/* Kopieren */
	while(*p && !isspace(*p) && maxlen--) *to++=*p++;
	*to=0;
}

static APTR buffmem;
static ULONG buffsize;
static struct SignalSemaphore buffsem;

void initbuffmem( void )
{
	InitSemaphore( &buffsem );
}

void exitbuffmem( void )
{
	ObtainSemaphore( &buffsem );
	if( buffmem )
		FreeMem( buffmem, buffsize );
}

void flushbuffmem( void )
{
	if( AttemptSemaphore( &buffsem ) )
	{
		if( buffmem )
		{
			FreeMem( buffmem, buffsize );
			buffmem = NULL;
		}
		ReleaseSemaphore( &buffsem );
	}
}

APTR allocbuffmem( int maxsize, int *realsizeptr )
{
	int realsize = maxsize;

	ObtainSemaphore( &buffsem );
	if( buffmem )
	{
		if( buffsize >= maxsize )
		{
			*realsizeptr = maxsize;
			return( buffmem );
		}
		FreeMem( buffmem, buffsize );
		buffmem = NULL;
	}

	for(;;)
	{
		buffmem = AllocMem( realsize, memf_no_expunge );
		if( buffmem )
			break;
		if( realsize > 256 )
			realsize /= 2;
		else
			Delay( 10 );
	}

	buffsize = *realsizeptr = realsize;
	return( buffmem );
}

void freebuffmem( void )
{
	if( buffsize >= 128000 )
	{
		FreeMem( buffmem, buffsize );
		buffmem = NULL;
	}
	ReleaseSemaphore( &buffsem );
}

char *StrDupPooled( APTR pool, char *string )
{
	char *new = LibAllocPooled( pool, strlen( string ) + 1 );
	if( new )
		strcpy( new, string );
	return( new );
}

void newdofrselfile( struct ogwin *ogw, UWORD id, char *title )
{
	char filename[108];
	char path[256],*p;

	filename[0]=0;
	p = ogreStringValue( ogw, id );
	strcpy( filename, filepart( p ) );
	strcpy( path, p );
	p = filepart( path );
	if( p )
		*p = 0;
	rtChangeReqAttr(fr[FR_PREFSMISC],RTFI_Dir,path,TAG_DONE);

	if(rtFileRequest(fr[FR_PREFSMISC],filename,title,
		RT_Screen,scr,RT_ReqPos,REQPOS_CENTERSCR,
		TAG_DONE)) {
			strcpy(path,fr[FR_PREFSMISC]->Dir);
			addpart( path, filename );
			ogreSetStringValue( ogw, id, path );
	}

}

void newdofrseldir( struct ogwin *ogw, UWORD id, char *title )
{
	char filename[108];
	char path[256],*p;

	filename[0]=0;
	p = ogreStringValue( ogw, id );
	strcpy( path, p );
	rtChangeReqAttr( fr[ FR_PREFSMISC ], RTFI_Dir, path, TAG_DONE);

	if( rtFileRequest( fr[ FR_PREFSMISC ],
		filename,
		title,
		RT_Screen, scr,
		RTFI_Flags, /*FREQF_SELECTDIRS |*/ FREQF_NOFILES,
		RT_ReqPos, REQPOS_CENTERSCR,
		TAG_DONE ))
	{
			strcpy( path, fr[ FR_PREFSMISC ] -> Dir);
			if( path[ 0 ] )
			{
				p = strchr( path, 0 ) - 1;
				if( *p != ':' && *p != '/' )
					strcat( p, "/" );
			}
			ogreSetStringValue( ogw, id, path );
	}
}

static BPTR lockstack[ 32 ];
static ULONG lockstackptr;

int pushdirlock( BPTR lock )
{
	lock = DupLock( lock );
	lockstack[ lockstackptr++ ] = CurrentDir( lock );
	return( 0 );
}

int pushdir( char *pfad )
{
	BPTR lock = Lock( pfad, SHARED_LOCK );

	if( !lock )
		return( IoErr() );

	lockstack[ lockstackptr++ ] = CurrentDir( lock );

	return( 0 );
}

static BPTR homelock;
void inithomedir( void )
{
	homelock = DupLock( MYPROC->pr_CurrentDir );
}
 
void pushhomedir( void )
{
	pushdirlock( homelock );
}

void freelockstack( void )
{
	while( lockstackptr )
	{
		UnLock( CurrentDir( lockstack[ --lockstackptr ] ) );
	}
	UnLock( homelock );
}

void popdir(void)
{
	if( lockstackptr )
	{
		UnLock( CurrentDir( lockstack[ --lockstackptr ] ) );
	}
	else
		Alert( 0x666 );
}

static FILE *logf;
static struct hlist *loghl;
void openlogmsg(char *betreff)
{
	char path[256];

	strcpy( path, prefs.datadir );
	addpart( path, "__mdlog.tmp" );

	if( isv37 )
		logf = ( FILE * ) Open( path, MODE_NEWFILE );
	else
		logf = fopen( path, "w" );

	if( !logf )
		return;

	loghl = hl_initheader();

	hl_addheader( loghl, "ABS", "MicroDot (Protokoll-Nachricht)" );
	hl_addheader( loghl, "MID", makemid() );
	makedateheader( path, time( 0 ) );
	hl_addheader( loghl, "EDA", path );
	hl_addheader( loghl, "BET", betreff );

}

void closelogmsg(void)
{
	if( logf )
	{
		struct mbrett *sp=findbrett("/»PROTOKOLL",0);
		struct pindex *pix;
		struct mail mail;
		char path[ 256 ];

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

		strcpy( path, prefs.datadir );
		addpart( path, "__mdlog.tmp" );

		if( isv37 )
			Close( ( BPTR ) logf );
		else
			fclose( logf );
		logf = NULL;

		header2mail( loghl, &mail );
		pix = msg_store( NULL, 0, path, -1,
			&mail.pufferID, &mail.mailID,
			loghl
		);

		hl_freeheader( loghl );

		if( pix )
		{
			mail.maillen = pix->datasize;
			storemail2ix( &mail, sp, NULL );
		}

		DeleteFile( path );
	}
}


void __stdargs printlog(char *s,...)
{
	if(logf)
	{
#ifndef MDV20
		if( !LocaleBase )
			replacebigd( s );
#endif
		if( isv37 )
			VFPrintf( ( BPTR ) logf,s,(((long)&s)+4));
#ifndef MDV20
		else
			vfprintf(logf,s,(va_list)(((long)&s)+4));
#endif
	}
}

#define MDS "UseConnectline"

char *makemid(void)
{
	static char mid[128];
	static USHORT midcount;
	char sproing[40];

	/* Netcall3.8 kompatible MsgID erzeugen */
	if( prefs.mode == MDM_N38 )
	{
		ULONG pncrc = crc32( prefs.pointname, strlen( prefs.pointname ) );

		num2b64( pncrc, sproing );
		num2b64( time( 0 ), &sproing[8] );
		num2b64( registerinfo.serie, &sproing[16] );

		sprintf( mid, "%lc%1.1s%3.3s%3.3s@%s",
			MDS[ midcount++ % strlen( MDS ) ],
			sproing,
			&sproing[8 + 1 ],
			&sproing[16],
			prefs.boxname );

		strupr( strchr( mid, '@' ) );
		return( mid );
	}

	/* RFC/ZConnect MsgId erzeugen */
	num2b64( time( 0 ), sproing );

	if( prefs.mode == MDM_RFC )
	{
		sprintf( mid, "%sMD%lxa%lcz%lx@%s%s",
			sproing,
			registerinfo.serie,
			MDS[ midcount++ % strlen( MDS ) ],
			midcount,
			prefs.pointname,
			prefs.boxdomain );
	}
	else
	{
		sprintf( mid, "%sMD%lxa%lcz%lx@%s.%s%s",
			sproing,
			registerinfo.serie,
			MDS[ midcount++ % strlen( MDS ) ],
			midcount,
			prefs.pointname,
			prefs.boxname,
			prefs.boxdomain );
	}

	strlwr(strchr(mid,'@'));
	return(mid);
}

void makedateheader( char *to, long t )
{
	char x[6];

	t -= timezone_offset;

	utunpk( t, x );

	sprintf(to,"%04ld%02ld%02ld%02ld%02ld%02ld%lc%lc%ld",
		x[0]+1970,
		x[1],x[2],x[3],x[4],x[5],
		timezone_dst ? 'S' : 'W',
		timezone_offset >= 0 ? '+' : '-',
		abs( timezone_offset) /3600 );
}

#include <exec/alerts.h>
void outofmem( void )
{
	if( Output() )
	{
#define WX(s) Write(Output(),s,strlen(s))
		WX( "\nMicroDot: *** Out of Memory!\n\007" );
	}
	else
		Alert( AG_NoMemory | AO_Unknown );
}

int astcsma( const char *s, const char *p )
{
	char buff[ 256 ];

	if( ParsePatternNoCase( p, buff, sizeof( buff ) ) >= 0 )
	{
		if( MatchPatternNoCase( buff, s ) )
		{
			return( 1 );
		}
	}
	return( 0 );
}
