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

#include <devices/serial.h>
#include <dos/dostags.h>
#include <libraries/owndevunit.h>
#include <dos.h>

#include <constructor.h>

struct Library *OwnDevUnitBase;

CONSTRUCTOR_P(openodu,25000)
{
	OwnDevUnitBase = OldOpenLibrary( ODU_NAME );
	return( 0 );
}

DESTRUCTOR_P(closeodu,25000)
{
	if( OwnDevUnitBase )
		CloseLibrary( OwnDevUnitBase );
}

#define BeginIO SendIO

static __aligned struct MsgPort *iorp,*iowp;
static struct MsgPort *tport;
__aligned struct IOExtSer ior;
__aligned struct IOExtSer iow;
static __aligned USHORT seropen,timeropen;

static struct timerequest tr;

static struct MsgPort *apport;
static struct AppIcon *appicon;
static struct DiskObject *appicondobj;
static ULONG apsig;

int linespeed;

static BPTR pdir;

static struct TextAttr gadta;
static char binfotxt1[ 256 ], binfotxt2[ 256 ];
static struct IntuiText binfoitext2 = { 0, 0, JAM2, 4,0, &gadta, binfotxt2, NULL };
static struct IntuiText binfoitext1 = { 0, 0, JAM2, 4,2, &gadta, binfotxt1, &binfoitext2 };
static struct Gadget bottombordgad;
static struct Image bottomclearimage = { 2,1, 0,0, 0, NULL, 0, 0, NULL };
static struct Gadget bottominfogadget = { &bottombordgad, 0, 0, 0, 0,
 GFLG_GADGHNONE | GFLG_RELBOTTOM | GFLG_RELWIDTH | GFLG_GADGIMAGE,
 GACT_BOTTOMBORDER,
 GTYP_BOOLGADGET | GTYP_GZZGADGET,
 &bottomclearimage, NULL, &binfoitext1, 0, NULL, 760
};

static long oldprio;

int nowdoicons;

extern ULONG tvsig;

extern int netcall_resume;

static void conprintf(char *s,...);

static void setpri(int p)
{
	oldprio = SetTaskPri( FindTask(NULL), p );
}

static void resetpri(void)
{
	SetTaskPri( FindTask(NULL), oldprio );
}

static void __stdargs treport( int l, char c, char *txt, ... )
{
	char *p = ( l ) ? binfotxt2 : binfotxt1;
	struct IntuiText *it = ( l ) ? &binfoitext2 : &binfoitext1;
	struct TextFont *tf;
	int maxch;
	int oldlen;

	if( !wbwindow )
	{
		ULONG *p = ( ULONG * ) ( ( ( ULONG ) ( &txt ) ) + 4 );
		preport( l, c, txt, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7] );
		return;
	}

	//oldlen = IntuiTextLength( it );
	tf = OpenFont( &gadta );
	dofmt(p,txt,(void*)(((long)&txt)+4));
	maxch = ogreTextFit( tf, p, bottomclearimage.Width - 4 );
	p[ maxch ] = 0;
	CloseFont( tf );
	it->FrontPen = c;

	/*if( IntuiTextLength( it ) < oldlen )
	{*/
		RefreshGList( &bottominfogadget, w, NULL, 1 );
/*	}
	else
	{
		PrintIText( w->BorderRPort, it, bottominfogadget.LeftEdge, bottominfogadget.TopEdge );
	}*/
}

void delpathcontents(char *path,char *ignore1,char *ignore2)
{
	char *buffer,*p;
	int size;
	long i;

	if( pushdir( path ) )
		return;

	buffer=AllocMem(16384,MEMF_CLEAR);
	if( !buffer )
	{
		outofmem();
		exit( 0 );
	}

	size = makefilelist( "", "#?", buffer, 16384 );
	p=buffer;

	while( size-- )
	{
		i=0;
		if(ignore1 && !stricmp(ignore1,p)) i=1;
		if(ignore2 && !stricmp(ignore2,p)) i=1;
		if(!i)
			DeleteFile(p);
		p=&p[strlen(p)+1];

	}
	FreeMem(buffer,16384);

	popdir();
}

struct mdtprefs mdtprefs;
void selectmdtprefs( char *name )
{
	memset( &mdtprefs, 0, sizeof( mdtprefs ) );
	if( !name || !name[ 0 ] )
	{
		strcpy( mdtprefs.name, "«Pointserver»" );
		strcpy( mdtprefs.device, prefs.modemdevice );
		strcpy( mdtprefs.modemdial, prefs.modemdial );
		strcpy( mdtprefs.modeminit, prefs.modeminit );
		strcpy( mdtprefs.modemhangup, prefs.modemhangup );
		mdtprefs.unit = prefs.modemunit;
		mdtprefs.baud = prefs.modembaud;
		mdtprefs.flags = prefs.modemflags;
		if( prefs.flags & MDF_TERM_IBM )
			mdtprefs.flags |= MDTF_IBM;
		if( prefs.modem_dropdtr )
			mdtprefs.flags |= MDTF_DROPDTR;
		mdtprefs.whichcolors = prefs.term_whichcolors;
	}
	else
	{
		struct AsyncFile *f;

		pushhomedir();
		f = OpenAsync( "microdot.mdtprefs", MODE_READ, sizeof( struct mdtprefs ) * 16 );
		popdir();

		if( f )
		{
			for(;;)
			{
				if( ReadAsync( f, &mdtprefs, sizeof( mdtprefs ) ) != sizeof( mdtprefs ) )
				{
					memset( &mdtprefs, 0, sizeof( mdtprefs ) );
					break;
				}
				if( !stricmp( mdtprefs.name, name ) )
					break;
			}
			CloseAsync( f );
		}
	}
}

void savemdtprefs( void )
{
	struct mdtprefs n;

	if( strcmp( mdtprefs.name, "«Pointserver»" ) )
	{
		BPTR f;

		pushhomedir();
		f = Open( "microdot.mdtprefs", MODE_OLDFILE );
		popdir();

		if( f )
		{
			for(;;)
			{
				if( Read( f, &n, sizeof( mdtprefs ) ) != sizeof( mdtprefs ) )
				{
					break;
				}
				if( !stricmp( n.name, mdtprefs.name ) )
				{
					Seek( f, -sizeof( mdtprefs ), OFFSET_CURRENT );
					Write( f, &mdtprefs, sizeof( mdtprefs ) );
					break;
				}
			}
			Close( f );
		}
	}
	else
	{
		if( mdtprefs.flags & MDTF_IBM )
			prefs.flags |= MDF_TERM_IBM;
		else
			prefs.flags &= ~MDF_TERM_IBM;
		prefs.term_whichcolors = mdtprefs.whichcolors;
	}
}

static int oduflag = 0;

static int initser( int termmode )
{
	long serflags = SERF_XDISABLED;
	int rc;

	oduflag = 0;

	if( OwnDevUnitBase )
	{
		char *oduerr;

		for(;;)
		{
			int rc;
			oduerr = AttemptDevUnit( mdtprefs.device, mdtprefs.unit, "MicroDot", SIGBREAKB_CTRL_E );

			if( !oduerr )
			{
				oduflag = TRUE;
				break;
			}

			rc = askreq( "OwnDevUnit-Meldung:\nDevice %s, Unit %ld\nkann nicht belegt werden.\n%s: %s", 
				"Wiederholen|Ignorieren|Abbruch",
				mdtprefs.device, mdtprefs.unit,
				*oduerr == 7 ? "Fehler" : "Aktueller Besitzer",
				*oduerr == 7 ? oduerr + 1 : oduerr
			);
	
			if( !rc )
			{
				return( -1 );
			}
			else if( rc == 2 )
				break;
		}
	}

	seropen=0;
	timeropen=0;

	tr.tr_node.io_Message.mn_ReplyPort=tport=CreatePort(0,0);
	OpenDevice("timer.device",UNIT_VBLANK,&tr,0);
	timeropen=1;

	if( mdtprefs.flags & 1 )
		serflags |= SERF_7WIRE;
	if( ( mdtprefs.flags & 2 ) && ( ! ( mdtprefs.flags & MDTF_7E1 ) ) )
		serflags |= SERF_RAD_BOOGIE;
	if( mdtprefs.flags & 4 )
		serflags |= SERF_SHARED;

	ior.IOSer.io_Message.mn_ReplyPort=iorp=CreatePort(0,0);
	ior.io_SerFlags=serflags;

reopen:
	if((rc=OpenDevice(mdtprefs.device,mdtprefs.unit,&ior,0)))
	{
		if( termmode && prefs.term_currentmdt[ 0 ] )
			rc = askreq("Fehler Nr. %ld beim Öffnen von\n%s, Unit %ld","Wiederholen|Mit Point-Konfiguration|Abbruch",rc,mdtprefs.device,mdtprefs.unit);
		else
			rc = askreq("Fehler Nr. %ld beim Öffnen von\n%s, Unit %ld","Wiederholen|Abbruch",rc,mdtprefs.device,mdtprefs.unit);
		if( rc == 1 )
			goto reopen;

		CloseDevice( &tr );
		timeropen = FALSE;
		DeletePort( tport );
		DeletePort(iorp);

		if( oduflag )
		{
			FreeDevUnit( mdtprefs.device, mdtprefs.unit );
			oduflag = FALSE;
		}

		return( ( rc == 2 ) ? -2 : -1 );
	}
	seropen=1;
	ior.IOSer.io_Command=SDCMD_SETPARAMS;
	ior.io_Baud=mdtprefs.baud;
	ior.io_StopBits=1;
	ior.io_RBufLen=8192;

	if( mdtprefs.flags & MDTF_7E1 )
	{
		ior.io_ReadLen = ior.io_WriteLen = 7;
		serflags |= SERF_PARTY_ON;
	}
	else
	{
		ior.io_ReadLen=ior.io_WriteLen=8;
	}

	ior.io_SerFlags=serflags;

	DoIO(&ior);
	iow=ior;
	iow.IOSer.io_Message.mn_ReplyPort=iowp=CreatePort(0,0);

	return(0);
}

static void exitser(void)
{
	if( oduflag )
	{
		FreeDevUnit( mdtprefs.device, mdtprefs.unit );
		oduflag = FALSE;
	}

	if(seropen) CloseDevice(&ior);
	if(timeropen) CloseDevice(&tr);
	if(tport) DeletePort(tport);
	if(iorp) DeletePort(iorp);
	if(iowp) DeletePort(iowp);
	seropen=0; timeropen=0;
	iorp=0;
	iowp=0;
}

static void sendat( char *cmd )
{
	char ch;

	while( *cmd )
	{
		ch = *cmd;
		if( ( *cmd == '^' ) || ( *cmd == '~' ) )
		{
			cmd++;
			Delay(25);
			continue;
		}
		if( *cmd == '|' )
			ch=13;
		cmd++;
		iow.IOSer.io_Length  = 1;
		iow.IOSer.io_Command = CMD_WRITE;
		iow.IOSer.io_Data    = &ch;
		DoIO(&iow);
	}
}

static void serputs( char *string )
{
	iow.IOSer.io_Length = strlen( string );
	iow.IOSer.io_Command = CMD_WRITE;
	iow.IOSer.io_Data = string;
	DoIO( &iow );

	iow.IOSer.io_Command = CMD_WRITE;
	if( prefs.flags2 & MDF2_NETCALLCRLF )
	{
		iow.IOSer.io_Length = 2;
		iow.IOSer.io_Data = "\r\n";
	}
	else
	{
		iow.IOSer.io_Length = 1;
		iow.IOSer.io_Data = "\r";
	}
	DoIO( &iow );

}

static void serialclear( void )
{
	iow.IOSer.io_Command = CMD_CLEAR;
	DoIO( &iow );
}

struct IOStdReq cr,cw;
static struct MsgPort *crp,*cwp;
static long conopen;

static struct ExtNewWindow tnw={0,0,0,0, (UBYTE)-1,(UBYTE)-1, MENUPICK|IDCMP_MENUHELP|IDCMP_REFRESHWINDOW|IDCMP_NEWSIZE|IDCMP_CLOSEWINDOW, ACTIVATE|BORDERLESS|WFLG_NW_EXTENDED|WFLG_BACKDROP, 0,0,0,0,0, 0,0,0,0, CUSTOMSCREEN,menuhelpti};
struct Window *twindow;
extern struct Menu *termmenustrip,*netcallmenustrip,*answermenustrip;
extern struct Gadget scrollgad;
extern struct TextFont *listfont;
static ULONG oldidcmpflags;

static void conresize( void )
{
	int d = ( w->BorderLeft + w->BorderRight );

	bottombordgad.GadgetRender = makebevelborder( w->Width - d - 6, bottominfogadget.Height, TRUE );
	bottomclearimage.Width     = w->Width - d - 10;

	treport( 0, binfoitext1.FrontPen, binfotxt1 );
	treport( 1, binfoitext2.FrontPen, binfotxt2 );

	RefreshWindowFrame( w );
}

extern int gadgetlistcount;

int initconsole( void )
{
	conopen		= 0;

	if( wbwindow )
	{
		int d = ( w->BorderLeft + w->BorderRight );

		removescrollgads();
		RemoveGList( w, &scrollgad, gadgetlistcount );

		gadta.ta_Name = prefs.gadfontname;
		gadta.ta_YSize = prefs.gadfontheight;

		twindow = w;

		oldidcmpflags = w->IDCMPFlags;
		ModifyIDCMP( w, tnw.IDCMPFlags );

		bottominfogadget.Width = - ( d + 6 );
		bottominfogadget.Height = ( prefs.gadfontheight + 2 ) * 2;
		bottominfogadget.TopEdge = -bottominfogadget.Height - 2;
		bottominfogadget.LeftEdge = w->BorderLeft + 2;

		bottombordgad = bottominfogadget;
		bottombordgad.Flags &= ~ GFLG_GADGIMAGE;
		bottombordgad.GadgetRender = makebevelborder( w->Width - d - 6, bottominfogadget.Height, TRUE );
		bottombordgad.GadgetText = NULL;
		bottombordgad.NextGadget = NULL;

		bottomclearimage.Width  = w->Width - d - 10;
		bottomclearimage.Height = bottominfogadget.Height - 2;
		bottomclearimage.Depth  = scr->RastPort.BitMap->Depth;
		binfoitext2.TopEdge     = 3 + prefs.gadfontheight;

		AddGList( w, &bottominfogadget, 0, 2, NULL );
		RefreshWindowFrame( w );
	}
	else
	{
		tnw.Screen	= scr;
		tnw.Height	= scr->Height-topoffs;
		tnw.TopEdge = topoffs;
		tnw.Width	= scr->Width;
		if( isv37 )
			tnw.Flags |= SIMPLE_REFRESH;
		twindow = OpenWindow( &tnw );
		if( !twindow )
		{
			displaybeep();
			return(-1);
		}
		SetFont( twindow->RPort, listfont );
	}

	cr.io_Message.mn_ReplyPort = crp = CreatePort( 0, 0 );
	cr.io_Data	 = twindow;
	cr.io_Length = sizeof(struct Window);

	if( isv39 )
		SetMaxPen( twindow->RPort, 255 );
	
	if( OpenDevice( "console.device", ( isv37 ) ? 3 : 0, &cr, 0 ) )
	{
		displaybeep();
		if( !wbwindow )
		{
			DeletePort( crp );
			CloseWindow( twindow );
		}
		return(-1);
	}
	conopen = 1;

	cw = cr;
	cw.io_Message.mn_ReplyPort = cwp = CreatePort( 0, 0 );	

	return(0);
}

static void exitconsole(void)
{
	if( conopen )
		CloseDevice( &cr );
	if( crp )
		DeletePort( crp );
	if( cwp )
		DeletePort( cwp );

	conopen = 0;
	crp = 0;
	cwp = 0;

	if( twindow )
	{
		if( wbwindow )
		{
			RemoveGList( w, &bottominfogadget, 2 );
			ClearMenuStrip( twindow );
			setmenuescflag();
			ModifyIDCMP( w, oldidcmpflags );
			SetRast( w->RPort, 0 );
			AddGList( w, &scrollgad, -1, gadgetlistcount, NULL );
			RefreshGList( &scrollgad, w, NULL, 4 );
			//makescrollergads();
		}
		else
		{
			ClearMenuStrip( twindow );
			CloseWindow( twindow );
		}
		twindow=0;
	}
	calcmaxpen();
}

int testcarrier(void)
{
	if( mdtprefs.flags & 8 )
		return( 1 );

	iow.IOSer.io_Command=SDCMD_QUERY;
	DoIO(&iow);
	return(!(iow.io_Status&(1<<5)));
}

struct uploadnode {
	struct MinNode n;
	char name[ 256 ];
};

static struct MinList uploadlist;
static APTR uploadlistpool;

static void inituploadlist( void )
{
	uploadlistpool = LibCreatePool(	MEMF_CLEAR, 4096, 2048 );
	NewList( ( struct List * ) &uploadlist );
}

static void exituploadlist( void )
{
	if( uploadlistpool )
		LibDeletePool( uploadlistpool );
}

#define ULID_LV 1
#define ULID_ADD 2
#define ULID_DEL 3
#define ULID_CLR 4
#define ULID_OK 5

static void doaddfiles( struct ogwin *ogw )
{
	struct rtFileList *fl,*fp;
	char name[256];

	name[ 0 ] = 0;
	fl=rtFileRequest(fr[FR_TERMUPLOAD],name,"Upload-Liste: Bitte Dateien wählen",
		RT_Window,twindow,RT_ReqPos,REQPOS_CENTERWIN,RT_LockWindow,TRUE,
		RTFI_Flags,FREQF_MULTISELECT,
		TAG_DONE
	);

	if(fl)
	{
		fp=fl;
		while( fp )
		{
			strcpy( name, fr[ FR_TERMUPLOAD ]->Dir );
			addpart( name, fp->Name );
			ogreLVAddEntry( ogw, ULID_LV, name, 2, 0 );
			fp=fp->Next;
		}
		rtFreeFileList( fl );
	}

}


static void makeuploadlist( void )
{
	struct ogwin *ogw;
	struct Window *iw;
	struct IntuiMessage *im;
	int    Done = FALSE;
	struct uploadnode *uln;
	int c;
	struct ogrevn *vn;
	int active = -1;
	struct AppWindow *aw = NULL;
	ULONG sig, sigw;

	ogw = ogreInitWindow( scr, 0, 0, "Upload-Liste" );

	ogreAddGroup( ogw, 0, OGFRAME_NONE, NULL );
	ogreAddList( ogw, 0, 0xff, NULL, ULID_LV, 60, 14, 0, NULL );
	ogreLVInit( ogw, ULID_LV );

	uln = ( struct uploadnode * ) uploadlist.mlh_Head;
	while( uln->n.mln_Succ )
	{
		ogreLVAddEntry( ogw, ULID_LV, uln->name, 2, NULL );
		uln = ( struct uploadnode * ) uln->n.mln_Succ;
	}

	ogreAddButton( ogw, 1 | OGB_ONENTER, 'o', "_Ok", ULID_OK );
	ogreAddHelp( ogw, 1 );
	ogreAddButton( ogw, 1, 'h', "_Hinzufügen", ULID_ADD );
	ogreAddButton( ogw, 1, 'l', "_Löschen", ULID_DEL );
	ogreAddButton( ogw, 1, 'a', "_Alle löschen", ULID_CLR );

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

	sigw = 1L << iw->UserPort->mp_SigBit;

	if( appicon )
		aw = AddAppWindow( 42, NULL, iw, apport, TAG_DONE );

	while( !Done )
	{
		ogreEnable( ogw, active != -1, ULID_DEL, 0 );

		sig = Wait( sigw | apsig );

		if( sig & apsig )
		{
			struct AppMessage *am;
			struct uploadnode *uln;
			struct WBArg *wba;

			while( ( am = ( struct AppMessage * ) GetMsg( apport ) ) )
			{
				if( !am->am_NumArgs )
				{
					ScreenToFront( scr );
				}
				else
				{
					wba = am->am_ArgList;
					while( am->am_NumArgs-- )
					{
						if( wba->wa_Name[ 0 ] )
						{
							char dirname[ 256 ];

							NameFromLock( wba->wa_Lock, dirname, 256 );
							AddPart( dirname, wba->wa_Name, 256 );
							ogreLVAddEntry( ogw, ULID_LV, dirname, 2, NULL );
						}
						wba++;
					}
				}
				ReplyMsg( am );
			}
			ogreLVRefresh( ogw, ULID_LV );
		}

		while( im = ogreIM( ogw ) )
		{
			if( im->Class == IDCMP_GADGETHELP)
				showguidenum( "term_uploadlist_gads", im->Code );
			else if( im->Class == IDCMP_GADGETUP )
			{
				switch( im->Code )
				{
					case ULID_OK:
						Done = 1;
						break;

					case ULID_LV:
						active = ogreValue( ogw, ULID_LV );
						break;

					case ULID_ADD:
						doaddfiles( ogw );
						ogreLVRefresh( ogw, ULID_LV );
						break;

					case ULID_DEL:
						if( active >= 0 )
						{
							ogreLVRemEntry( ogw, ULID_LV, active );
							ogreLVRefresh( ogw, ULID_LV );
						}
						active = -1;
						break;

					case ULID_CLR:
						ogreLVInit( ogw, ULID_LV );
						ogreLVRefresh( ogw, ULID_LV );
						break;
				}
			}
			ogreIMReply( ogw, im );
		}
	}

	exituploadlist();
	inituploadlist();

	for( c = 0; ; c++ )
	{
		vn = ogreLVGetEntry( ogw, ULID_LV, c );
		if( !vn )
			break;
		uln = LibAllocPooled( uploadlistpool, sizeof( *uln ) );
		strcpy( uln->name, vn->txt );
		AddTail( ( struct List * ) &uploadlist, ( struct uploadnode * ) uln );
	}

	if( aw )
		RemoveAppWindow( aw );

	ogreExitWindow( ogw );
}


static void douploadlist(void)
{
	char **filelist;
	long count;
	int c;
	void *winlock;
	struct uploadnode *uln;

	if( GetNumEntries( &uploadlist ) )
	{
		winlock=rtLockWindow(twindow);

		count = GetNumEntries( &uploadlist );

		filelist=myAllocVec((count+1)*4,MEMF_CLEAR);

		for(c=0; c<count; c++)
		{
			uln = ( struct uploadnode * ) RemHead( &uploadlist );
			filelist[ c ] = uln->name;
			AddTail( &uploadlist, ( struct Node * ) uln );
		}

		ior.IOSer.io_Command=CMD_CLEAR;
		DoIO(&ior);		

		setpri(5);
		setzmodemmode( prefs.flags2 & MDF2_TERM_ZM8K );
		c = xpr_send(&ior,&iow,-1,filelist);
		resetpri();

		myFreeVec(filelist);

		/*ior.IOSer.io_Command=CMD_CLEAR;
		DoIO(&ior);*/

		rtUnlockWindow(twindow,winlock);

		conprintf( "\rDateiübertragung/Senden %s.\n", c ? "erfolgreich" : "abgebrochen" );

		if( c )
		{
			exituploadlist();
			inituploadlist();
		}

	}
	else
		displaybeep();
}


static void doupload(void)
{
	struct rtFileList *fl,*fp;
	char **filelist;
	char name[108];
	long count;
	int c;
	void *winlock;

	name[0]=0;
	fl=rtFileRequest(fr[FR_TERMUPLOAD],name,"Z-Modem-Upload: Bitte Dateien wählen",
		RT_Window,twindow,RT_ReqPos,REQPOS_CENTERWIN,RT_LockWindow,TRUE,
		RTFI_Flags,FREQF_MULTISELECT,
		TAG_DONE
	);

	if(fl)
	{
		winlock=rtLockWindow(twindow);
		pushdir(fr[FR_TERMUPLOAD]->Dir);
		fp=fl;
		for(count=0; fp; count++, fp=fp->Next);

		filelist=myAllocVec((count+1)*4,MEMF_CLEAR);
		fp=fl;
		for(c=0; c<count; c++)
		{
			filelist[c]=fp->Name;
			fp=fp->Next;
		}

		ior.IOSer.io_Command=CMD_CLEAR;
		DoIO(&ior);		

		setpri(5);
		setzmodemmode( prefs.flags2 & MDF2_TERM_ZM8K );
		c = xpr_send(&ior,&iow,-1,filelist);
		resetpri();

		myFreeVec(filelist);

		rtFreeFileList(fl);

		/*ior.IOSer.io_Command=CMD_CLEAR;
		DoIO(&ior);*/

		popdir();

		rtUnlockWindow(twindow,winlock);

		conprintf( "\rDateiübertragung/Senden %s.\n", c ? "erfolgreich" : "abgebrochen" );

	}
}


static void dodownload(void)
{
	void *winlock;
	char fileb[256];
	int c;

	pushdir( prefs.term_downloadpath );

	nowdoicons = TRUE;
	winlock=rtLockWindow(twindow);
	/*ior.IOSer.io_Command = CMD_CLEAR;
	DoIO(&ior);*/
	fileb[0]=0;
	setpri(5);
	c = xpr_receive(&ior,&iow,-1);
	resetpri();
	rtUnlockWindow(twindow,winlock);
	/*ior.IOSer.io_Command=CMD_CLEAR;
	DoIO(&ior);*/
	nowdoicons = FALSE;

	popdir();

	conprintf( "\rDateiübertragung/Empfang %s.\n", c ? "erfolgreich" : "abgebrochen" );
}

static void qtimer(void)
{
	tr.tr_time.tv_micro=0;
	tr.tr_time.tv_secs=1;
	tr.tr_node.io_Command=TR_ADDREQUEST;
	SendIO(&tr);
}

static void conprint(char *s)
{
	cw.io_Data=s;
	cw.io_Length=-1;
	cw.io_Command=CMD_WRITE;
	DoIO(&cw);
}

static void conprintf(char *s,...)
{
	char dat[128];

	dofmt(dat,s,(void*)(((long)&s)+4));
	conprint("\x1b[3;32m");
	conprint(dat);
	conprint("\x1b[0m");

}

static	APTR oldrdata;
static	LONG oldrlen;
static void serclose_temp( void )
{
	oldrdata = ior.IOSer.io_Data;
	oldrlen = ior.IOSer.io_Length;

	/* DTR aus; dazu Device kurz schließen */
	AbortIO( &ior );
	WaitIO( &ior );

	CloseDevice( &ior );
}

static void seropen_temp( int queue )
{
	if( OpenDevice( mdtprefs.device, mdtprefs.unit, &ior, 0 ) )
	{
		displaybeep();
		return;
	}
	iow.IOSer.io_Device = ior.IOSer.io_Device;
	iow.IOSer.io_Unit = ior.IOSer.io_Unit;

	ior = iow;
	ior.IOSer.io_Message.mn_ReplyPort = iorp;	
	ior.IOSer.io_Command = SDCMD_SETPARAMS;
	DoIO( &ior );
	ior.IOSer.io_Data = oldrdata;
	ior.IOSer.io_Length = oldrlen;
	ior.IOSer.io_Command = CMD_READ;
	if( queue )
		BeginIO( &ior );
}

static void hangup( void )
{
	if( mdtprefs.flags & MDTF_DROPDTR )
	{
		serclose_temp();
		Delay( 42 );
		seropen_temp( TRUE );
		Delay( 10 );
	}
	else
		Delay( 30 );
	sendat( mdtprefs.modemhangup );
}

static void cursoron( void )
{
	conprintf( "\x1b[ p" );
}
static void cursoroff( void )
{
	conprintf( "\x1b[0 p" );
}


static char *getphonefrom( char *phone, int n )
{
	int pc=0;
	char *p = phone;
	static char temp[80];
	int offs[ 32 ];

	do
	{
		p = stpblk( p );
		if( !*p )
			break;
		offs[ pc++ ] = p - phone;
	} while( ( p = strchr( p, ' ' ) ) );

	if( !pc )
		return( "" );

	n = n % pc;
	strcpy( temp, &phone[ offs[ n ] ] );
	p = strchr( temp, ' ' );
	if( p )
		*p=0;
	return( temp );
}

static char *getphone( int n )
{
	return( getphonefrom( prefs.phone, n ) );
}


#define RBSIZE 16
static char roundbuffer[RBSIZE];

static void putrb(UBYTE ch)
{
	memcpy(&roundbuffer[0],&roundbuffer[1],RBSIZE-1);
	roundbuffer[RBSIZE-1]=ch;
}

static void putrb7(UBYTE ch)
{
	/* TAB, SPACE, BELL */
	if( ( ch == 9 ) || ( ch == 32 ) || ( ch == 7 ) || ( ch == 10 ) ||( ch == 13 ) )
		return;

	memcpy(&roundbuffer[0],&roundbuffer[1],RBSIZE-1);
	roundbuffer[RBSIZE-1]=ch;
}

static int testrb(char *s)
{
	long sl=strlen(s);
	long x=RBSIZE-sl;

	return(!strnicmp(s,&roundbuffer[x],sl));
}

static int testrbzdl(void)
{
	return(!strncmp(ZMODEMAUTODOWNLOAD,&roundbuffer[RBSIZE-strlen(ZMODEMAUTODOWNLOAD)],strlen(ZMODEMAUTODOWNLOAD)));
}
static int testrbzul(void)
{
	return(!strncmp(ZMODEMAUTOUPLOAD,&roundbuffer[RBSIZE-strlen(ZMODEMAUTOUPLOAD)],strlen(ZMODEMAUTOUPLOAD)));
}

int checkmenustate(struct Menu *strip,USHORT menunum)
{
	struct MenuItem *mit=ItemAddress(strip,menunum);
	return(mit && mit->Flags&CHECKED);
}

static FILE *openlog(char *name)
{
	FILE *f=fopen(name,"a");

	if(!f) f=fopen(name,"w");

	if(!f) {
		askreq("Kann Logfile\n%s\nnicht öffnen (%ld)\n%s","Abbruch",name,_OSERR, errorstring( _OSERR ) );
	}
	return(f);
}

static int callbymodem( char *name, char *number, char *username, char *password, char *dialprefix, int doautologin )
{
	int tries = prefs.dialretries;
	char *phone;
	long timeout;
	void *iop1, *iop2;
	long sigs, tsig, ssig, csig;
	int connect = 0;
	char conr, serr;
	ULONG phonetrycount = 0;
	int cq = FALSE, tq, sq;
	int loginmode = 0;
	int notfirst = FALSE;

	tsig = 1<<tr.tr_node.io_Message.mn_ReplyPort->mp_SigBit;
	ssig = 1<<ior.IOSer.io_Message.mn_ReplyPort->mp_SigBit;
	csig = 1<<cr.io_Message.mn_ReplyPort->mp_SigBit;

	iop1 = cr.io_Data;
	AbortIO( &cr );
	WaitIO( &cr );

	iop2 = ior.IOSer.io_Data;
	AbortIO( &ior );
	WaitIO( &ior );

	AbortIO( &tr );
	WaitIO( &tr );

	twindow->Flags |= RMBTRAP;

	cursoroff();

	while( tries-- && ( connect != -2 ) )
	{
		if( notfirst )
		{
			int timeout = prefs.retrydelay;

			if( cq )
			{
				AbortIO( &cr );
				WaitIO( &cr );
			}
			cr.io_Command = CMD_CLEAR;
			DoIO( &cr );

			cr.io_Command = CMD_READ;
			cr.io_Length 	= 1;
			cr.io_Data 	= &conr;
			BeginIO( &cr );
			cq = TRUE;

			while( timeout > 0 )
			{		
				conprintf( "\rAnwahlpause; noch %ld Sekunden...  ", timeout-- );
				Delay( 50 );
				if( CheckIO( &cr ) )
					break;
			}
		}
		notfirst = TRUE;

		if( !number )
			phone = getphone( phonetrycount++ );
		else
			phone = getphonefrom( number, phonetrycount++ );

		loginmode = 0;

		conprintf( "\r%s unter %s anrufen (noch %lD Versuche)...", name, phone, tries );
		sendat( dialprefix );
		sendat( phone );
		sendat( "|" );

		timeout = prefs.dialtimeout;
		connect = 0;

		cq = FALSE;
		tq = FALSE;
		sq = FALSE;

		SetSignal( 0, tsig | ssig | csig );

		while( timeout && ( !connect || connect == 1 ) )
		{
			if( !tq )
			{
				if( connect != 1 )
					conprintf( "%02ld:%02ld\b\b\b\b\b",
						timeout / 60,
						timeout % 60 );
				qtimer();
				tq = TRUE;
			}

			if( !cq )
			{
				cr.io_Command = CMD_READ;
				cr.io_Length 	= 1;
				cr.io_Data 	= &conr;
				BeginIO( &cr );
				cq = TRUE;
			}

			if( !sq )
			{
				ior.IOSer.io_Command 	= CMD_READ;
				ior.IOSer.io_Data	= &serr;
				ior.IOSer.io_Length	= 1;
				BeginIO( &ior );
				sq = TRUE;
			}

			sigs = mWait( tsig | ssig | csig );

			if( sigs & tsig )
			{
				WaitIO( &tr );
				tq = FALSE;
				timeout--;
			}

			if( sigs & csig )
			{
				WaitIO( &cr );
				cq = FALSE;

				if( conr == 0x1b )
					connect = -2;
				else
					connect = -1;
				break;
			}

			if( sigs & ssig )
			{
				WaitIO( &ior );
				sq = FALSE;

				putrb7( serr );

				if( !connect && testrb( "CONNECT" ) )
				{
					conprintf( "\nVerbindung hergestellt!\n\n\x1b[0mCONNECT " );
					connect = ( doautologin ) ? 1 : 4;
					continue;
				}
				else if( testrb( "BUSY" ) && !connect )
					connect = 2;
				else if( testrb( "NO CARRIER" ) || testrb( "NO DIALTONE" ) || testrb( "DIAL LOCKED" ) )
					connect = 3;

				if( connect == 1 && doautologin )
				{
					if( !loginmode )
					{
						serr = ibm2iso( serr );
						cw.io_Data    = &serr;
						cw.io_Length  = 1;
						cw.io_Command = CMD_WRITE;
						DoIO( &cw );
					}

					if( testrb( "username:" ) || testrb( "login:" ) )
					{
						loginmode = TRUE;
						conprintf( "\rUsername...\n" );
						serialclear();
						serputs( username );

						if( !password[ 0 ] )
							connect = 4;
					}
					else if( testrb( "pressESCtwice" ) )
					{
						serputs( "\033\033" );
					}
					else if( loginmode && ( testrb( "password:" ) || testrb( "passwort:" ) ) )
					{
						conprintf( "Passwort...\n" );
						serialclear();
						serputs( password );
						connect = 4;
					}
				}
			}
		}

		if( tq )
		{
			AbortIO( &tr );
			WaitIO( &tr );
		}
		if( sq )
		{
			AbortIO( &ior );
			WaitIO( &ior );
		}
		if( cq )
		{
			AbortIO( &cr );
			WaitIO( &cr );
		}

		if( connect == 1 || connect == 4 )
		{
			break;
		}
		else if( connect == 2 )
		{
			conprintf( "Box ist besetzt.\n" );
		}
		else if( connect == 3 )
		{
			conprintf( "Keine Verbindung.\n" );
		}
		else if( connect == 0 )
		{
			conprintf( "Timeout.\n" );
		}
		else if( connect < 0 )
		{
			conprintf( "Abgebrochen!\n" );
			sendat( "|^" );
			if( connect == -2 )
			{
				conprintf( "\n" );
				iow.IOSer.io_Command = CMD_CLEAR;
				DoIO( &iow );
				break;
			}
		}

		Delay( 60 );

		iow.IOSer.io_Command = CMD_CLEAR;
		DoIO( &iow );
	}

	cursoron();

	cr.io_Data = iop1;
	cr.io_Length = 1;
	cr.io_Command = CMD_READ;
	BeginIO( &cr );

	ior.IOSer.io_Data = iop2;
	ior.IOSer.io_Length = 1;
	ior.IOSer.io_Command = CMD_READ;
	BeginIO( &ior );

	qtimer();

	twindow->Flags &= ~RMBTRAP;

	return( ( connect == 1 || connect == 4 ) );
}


static void calluser(void)
{
	struct user u;

	if(douserrequser(&u))
	{
		if(!u.telefon[0]) conprintf("Für User %s ist keine Telefonnummern eingetragen.\n",UNAME(u));
		else
		{
			callbymodem( UNAME( u ), u.telefon, 0, 0, mdtprefs.modemdial, FALSE );
		}
	}
}

static struct mdphone *dialasap;
char lastboxdialed[ 40 ] = { "KEIN TELEFONBUCHEINTRAG" };
static int callphone( void )
{
	struct mdphone *m;

	if( dialasap )
	{
		m = dialasap;
		dialasap = NULL;
	}
	else
	{
		m = dotermphonesel();
	}
	if( m )
	{
		strcpy( lastboxdialed, m->name );
		if( stricmp( prefs.term_currentmdt, m->prefs ) )
		{
			strcpy( prefs.term_currentmdt, m->prefs );
			dialasap = m;
			return( TRUE );
		}
		callbymodem( m->name, m->phone, m->username, m->password, mdtprefs.modemdial, m->autologin );
	}
	return( 0 );
}


static void dotermhelp(void)
{
	showguide("menu_brett_0_3");
}

static void callnumber( void )
{
	int rc;
	static char buffer[ 128 ];

	rc = rtGetString( buffer, 128,
		NULL,
		rinfo,
		RTGS_TextFmt, "Beliebige Telefonnummer anrufen:",
		TAG_DONE );

	if( rc )
		callbymodem( buffer, buffer, 0, 0, mdtprefs.modemdial, FALSE );
		
}


static void insertfkey(struct IOExtSer *iow,long fkey)
{
	static char key[128];
	UBYTE *p,*p2;

	if(fkey<0) { dotermhelp(); return; }
	if(fkey>19) return;
	p=prefs.fkeys[fkey];
	p2=key;
	while(*p) {
		if(*p=='|') { *p2++=13; p++; }
		else *p2++=*p++;
	}
	*p2=0;
	iow->IOSer.io_Data=key;
	iow->IOSer.io_Length=strlen(key);
}

extern char *download;

static int doterminal2( void )
{
	UBYTE crch,srch; /* console & serial read chars */
	ULONG ssig, csig, wsig, sigs, tsig;
	time_t t,t2,t3;
	USHORT carrier,check;
	struct IntuiMessage *im;
	ULONG itemnum,menunum;
	long doexit=0;
	char serbuf[256],*p,csibuf[4];
	int c,d;
	int dolog = ( prefs.flags & MDF_TERM_LOG );
	int hexmode = FALSE;

	if( isv37 )
	{
		if( GetVar( "MD_TERM_HEX", serbuf, 256, 0 ) >= 0 )
			hexmode = TRUE;
	}

retrycfg:
	selectmdtprefs( prefs.term_currentmdt );
	linespeed = prefs.modembaud;
	if( !mdtprefs.name[ 0 ] )
	{
		if( askreq( "Terminal-Konfiguration\n%s\nnicht gefunden.", "Weiter mit Point-Konfiguration|Abbruch", prefs.term_currentmdt ) )
		{
			prefs.term_currentmdt[ 0 ] = 0;
			goto retrycfg;
		}
		else
			return( 0 );
	}

	c = initser( TRUE );
	if( c )
	{
		if( c == -2 )
		{
			prefs.term_currentmdt[ 0 ] = 0;
			goto retrycfg;
		}
		return( 0 );
	}
	if(initconsole())
	{
		exitser();
		return( 0 );
	}

	if( isv37 && WorkbenchBase )
	{
		apport = CreateMsgPort();
		pushhomedir();
		appicondobj = GetDiskObject( "DefIcons/UploadList" );
		if( !appicondobj )
			appicondobj = GetDefDiskObject( WBPROJECT );
		popdir();
		appicon = AddAppIcon( 42, NULL, "MicroDot-Upload-Liste", apport, NULL, appicondobj, TAG_DONE );
		if( appicon )
			apsig = 1L << apport->mp_SigBit;
	}

	treport( 0, 2, "Terminal-Modus %s (%s, Unit %ld, %lD bps%s%s%s)",mdtprefs.name, mdtprefs.device,mdtprefs.unit,mdtprefs.baud,
		(mdtprefs.flags&1)?", RTS/CTS":"",
		(mdtprefs.flags&2)?", HISPEED":"",
		(mdtprefs.flags&4)?", SHARED":"");
	treport( 1, 2, "Online: 00:00:00" );

	tv_init();

	ClearMenuStrip( twindow );
	SetMenuStrip( twindow, termmenustrip );

	if( prefs.term_currentmdt[ 0 ] )
		OnMenu( twindow, FULLMENUNUM( 3, 1, 0 ) );
	else
		OffMenu( twindow, FULLMENUNUM( 3, 1, 0 ) );

	ssig = 1L<<iorp->mp_SigBit;
	wsig = 1L<<twindow->UserPort->mp_SigBit;
	csig = 1L<<crp->mp_SigBit;
	tsig = 1L<<tport->mp_SigBit;

	cr.io_Data=&crch;
	cr.io_Length=1;
	cr.io_Command=CMD_READ;
	BeginIO(&cr);

	ior.IOSer.io_Data=&srch;
	ior.IOSer.io_Length=1;
	ior.IOSer.io_Command=CMD_READ;
	BeginIO(&ior);

	t=0;
	carrier=testcarrier();

	if( carrier )
		time( &t2 );

	qtimer();

#define	isibm ( mdtprefs.flags & MDTF_IBM )
#define	autodl ( prefs.flags & MDF_TERM_AUTODL )
#define	autoul ( prefs.flags & MDF_TERM_AUTOUL )

	ClearPointer( twindow );

	if( !wbwindow && mdtprefs.whichcolors )
		term_setcolors();

	inituploadlist();

	while( !doexit )
	{
		if( dialasap )
			callphone();

		sigs = mWait( ssig | csig | wsig | tsig | tvsig | apsig );

		if( sigs & apsig )
		{
			struct AppMessage *am;
			struct uploadnode *uln;
			struct WBArg *wba;

			while( ( am = ( struct AppMessage * ) GetMsg( apport ) ) )
			{
				if( !am->am_NumArgs )
				{
					ScreenToFront( scr );
				}
				else
				{
					wba = am->am_ArgList;
					while( am->am_NumArgs-- )
					{
						if( wba->wa_Name[ 0 ] )
						{
							uln = LibAllocPooled( uploadlistpool, sizeof( *uln ) );
							if( uln )
							{
								NameFromLock( wba->wa_Lock, uln->name, 256 );
								AddPart( uln->name, wba->wa_Name, 256 );
								AddTail( ( struct List * ) &uploadlist, ( struct Node * ) uln );
							}
						}
						wba++;
					}
				}
				ReplyMsg( am );
			}
		}

		if( sigs & wsig )
		{
			while( ( im = ( struct IntuiMessage * )	GetMsg( twindow->UserPort)))
			{
				if(im->Class==IDCMP_MENUHELP)
				{
					domenuhelp( "term", im );
					ReplyMsg( im );
				}
				else if( im->Class == IDCMP_CLOSEWINDOW )
				{
					ReplyMsg( im );
					doexit = 1;
				}
				else if( im->Class == IDCMP_NEWSIZE )
				{
					ReplyMsg( im );
					conresize();
				}
				else if( im->Class == IDCMP_REFRESHWINDOW )
				{
					ReplyMsg( im );
					BeginRefresh( w );
					EndRefresh( w, TRUE );
				}
				else if( im->Class == IDCMP_MENUPICK )
				{
					itemnum = ITEMNUM( im->Code );
					menunum = MENUNUM( im->Code );
					ReplyMsg( im );

					if(!menunum) switch(itemnum)
					{
						case 0: conprintf("\x1b\x63\f"); break;
						case 2: 
							callbymodem( prefs.boxname, prefs.phone, prefs.username, prefs.userpassword, prefs.modemdial, TRUE /*prefs.flags2 & MDF2_TERM_AUTOLOGIN*/ );
							break;
						case 3: if( callphone() )
									doexit = 2;
								break;
						case 4: calluser(); break;
						case 5: callnumber(); break;
						case 7: conprintf("Auflegen...\n"); hangup(); break;
						case 9: dotermhelp(); break;
						case 11: doexit=1; break;
					}
					else if(menunum==1) switch(itemnum)
					{
						case 0: AbortIO(&ior); WaitIO(&ior);
							doupload();
							ior.IOSer.io_Data=&srch;
							ior.IOSer.io_Length=1;
							ior.IOSer.io_Command=CMD_READ;
							BeginIO(&ior);
							break;
						case 1: AbortIO(&ior); WaitIO(&ior);
							dodownload();
							ior.IOSer.io_Data=&srch;
							ior.IOSer.io_Length=1;
							ior.IOSer.io_Command=CMD_READ;
							BeginIO(&ior);
							break;

						case 3:
							if( checkmenustate( termmenustrip, FULLMENUNUM( 1,3, NOSUB ) ) )
								prefs.flags2 |= MDF2_TERM_ZM8K;
							else
								prefs.flags2 &= ~MDF2_TERM_ZM8K;
							break;

						case 5:
							makeuploadlist();
							break;

						case 6:
							AbortIO(&ior); WaitIO(&ior);
							douploadlist();
							ior.IOSer.io_Data=&srch;
							ior.IOSer.io_Length=1;
							ior.IOSer.io_Command=CMD_READ;
							BeginIO(&ior);
							break;

						case 8:
							AbortIO(&ior);
							WaitIO(&ior);
							AbortIO(&cr);
							WaitIO(&cr);
							download = prefs.term_downloadpath;
							hydra_xfer( &uploadlist );
							ior.IOSer.io_Data=&srch;
							ior.IOSer.io_Length=1;
							ior.IOSer.io_Command=CMD_READ;
							BeginIO( &ior );
							cr.io_Data=&crch;
							cr.io_Length=1;
							cr.io_Command=CMD_READ;
							BeginIO( &cr );
							break;

					}
					else if(menunum==2) switch(itemnum)
					{
						case 0: dolog = checkmenustate( termmenustrip, FULLMENUNUM( 2,0, NOSUB ) ); break;
						case 2: tvsig = tv_open( twindow ); break;
						case 4: tv_clear(); break;
						case 5: tv_save(); break;
						case 6: tv_save_proto(); break;
					}
					else if(menunum==3) switch(itemnum)
					{
						case 0: if( dotermsel() )
									doexit = 2;
								break;
						case 1: if( dotermserial() )
									doexit = 2;
								break;
						case 2: dotermterm(); break;
						case 4: dotermfkey(); break;
						case 5: dotermtransfer(); break;
						case 7: dotermphone(); break;
					}
				}
				else ReplyMsg( im );
			}
		}


		if( ( sigs & csig ) && CheckIO( &cr ) )
		{
			WaitIO( &cr );

			if(crch == 0x9b)
			{
				memset( csibuf, 0, 4 );
				iow.IOSer.io_Data = NULL;

				/* CSI received */
				cr.io_Command 	= CMD_READ;
				cr.io_Length  	= 1;
				cr.io_Data		= &csibuf[0];
				DoIO( &cr );
				if( isdigit( csibuf[0] ) || csibuf[0] == '?' )
				{
					cr.io_Data = &csibuf[1];
					DoIO( &cr );
					if( csibuf[0]=='?' && csibuf[1]=='~')
					{
						insertfkey( &iow, -1 );
						goto contcsi;
					}

					if( isdigit(csibuf[1]) )
					{
						cr.io_Data = &csibuf[2];
						DoIO( &cr );
						if( csibuf[2]=='~' )
						{
							insertfkey( &iow, atoi( csibuf ) );
							goto contcsi;
						}
					}
					else if( csibuf[1]=='~' )
					{
						insertfkey( &iow, atoi(csibuf) );
						goto contcsi;
					}
				}
writecsi:
				iow.IOSer.io_Command=CMD_WRITE;
				iow.IOSer.io_Data="\x1b[";
				iow.IOSer.io_Length=2;
				DoIO( &iow );
				c = strlen( csibuf );
				if( c )
				{
					iow.IOSer.io_Data	=	csibuf;
					iow.IOSer.io_Length	=	c;
				}
contcsi:
				cr.io_Data=&crch;
			}
			else
			{
				if(isibm) crch=iso2ibm(crch);
				iow.IOSer.io_Data=&crch;
				iow.IOSer.io_Length=1;
			}
			if( iow.IOSer.io_Data )
			{
				iow.IOSer.io_Command=CMD_WRITE;
				DoIO(&iow);
			}
			cr.io_Length = 1;
			cr.io_Command = CMD_READ;
			BeginIO(&cr);
		}
		if( ( sigs & ssig ) && CheckIO(&ior))
		{
			if( hexmode )
			{
				conprintf( "<%02lx:%lc>", srch, isprint( srch ) ? srch : '.' );
				if( srch == 10 || srch == 13 )
					conprintf( "\n" );
				goto contser;
			}

			WaitIO(&ior);
			if(isibm)
				srch=ibm2iso(srch);
			cw.io_Command=CMD_WRITE;
			cw.io_Data=&srch;
			cw.io_Length=1;
			if( dolog )
			{
				SendIO(&cw);
				tv_add( &srch, 1 ); 
				WaitIO(&cw);
			} else DoIO(&cw);

			/* Auto-Download? */
			if(autodl || autoul ) {
				putrb(srch);
				if(autodl && testrbzdl()) dodownload();
				if(autoul && testrbzul()) doupload();
			}

			/* Weitere Zeichen? */
retest:
			ior.IOSer.io_Command=SDCMD_QUERY;
			DoIO(&ior);
			if(ior.IOSer.io_Actual)
			{
				ior.IOSer.io_Length=min(ior.IOSer.io_Actual,256);
				ior.IOSer.io_Command=CMD_READ;
				ior.IOSer.io_Data=serbuf;
				DoIO(&ior);
				c=ior.IOSer.io_Actual;
				if(isibm) bibm2iso(serbuf,c);
				cw.io_Command=CMD_WRITE;
				cw.io_Data=serbuf;
				cw.io_Length=c;
				if( dolog ) {
					SendIO(&cw);
					tv_add( serbuf, c );
					WaitIO(&cw);
				} else DoIO(&cw);

				/* Auto-Download? */
				if( autodl || autoul ) {
					p=serbuf;
					while(c--) {
						putrb(*p++);
						if(autodl && testrbzdl()) { dodownload(); break; }
						if(autoul && testrbzul()) { doupload(); break; }
					}
				}

				goto retest;
			}

			tv_update();
			
contser:
			ior.IOSer.io_Data=&srch;
			ior.IOSer.io_Length=1;
			ior.IOSer.io_Command=CMD_READ;
			BeginIO(&ior);
		}

		if( sigs & tvsig )
			tv_proc();

		if( sigs & tsig )
		{
			/*AbortIO(&tr);*/
			WaitIO(&tr);
			check=testcarrier();
			treport(1,2,"Online: %02ld:%02ld:%02ld %s %s",
				(t/3600)%60,(t/60)%60,t%60,
				(check)?((mdtprefs.flags&8)?"(Carrier ignorieren)":"(Verbindung besteht)"):"",
				(dolog)?"(Mitschnitt aktiv)":"");
	
			if(carrier && !check) {
				carrier=0;
			}	
			if(!carrier & check) {
				carrier=1;
				time(&t2);
			}

			if(check) {
				time(&t3);
				if(t2!=t3) {
					t+=t3-t2;
				}
				t2=t3;
			}

			qtimer();
		}
			
		if( doexit == 1 )
		{
			c = testcarrier() && !( mdtprefs.flags & 8 );
			d = tv_changed();

			if( c || d )
			{
				doexit = askreq( "Wollen Sie das Terminal wirklich beenden?\n%s%s",
					"Beenden|Weitermachen",
					( c ) ? "\n· Es ist noch eine Verbindung vorhanden!" : "",
					( d ) ? "\n· Der Mitschnitt-Puffer wurde nicht gespeichert!" : "" );
			}
		}
	}			

	AbortIO(&cr); WaitIO(&cr);
	AbortIO(&ior); WaitIO(&ior);
	AbortIO(&tr); WaitIO(&tr);

	tv_exit();

	if( appicon )
		RemoveAppIcon( appicon );
	if( appicondobj )
		FreeDiskObject( appicondobj );
	if( apport )
		DeleteMsgPort( apport );

	exituploadlist();

	if( dolog )
		prefs.flags |= MDF_TERM_LOG;
	else
		prefs.flags &=~ MDF_TERM_LOG;

	ClearMenuStrip( twindow );

	exitser();
	exitconsole();

	treport(0,0,"");
	treport(1,0,"");

	if( !wbwindow )
	{
		if( prefs.usecustomcolors )
			setcolors( scr );
		else
			setwbcolors( scr );
	}

	return( doexit == 2 );
}

void doterminal( void )
{
	while( doterminal2() );
}

static void writecs(char*s)
{
	iow.IOSer.io_Command=cw.io_Command=CMD_WRITE;
	iow.IOSer.io_Length=cw.io_Length=strlen(s);
	iow.IOSer.io_Data=cw.io_Data=s;
	SendIO(&iow); DoIO(&cw); WaitIO(&iow);
}

static void sendzeros(void)
{
	ULONG zero[2]={0,0};

	iow.IOSer.io_Data=zero;
	iow.IOSer.io_Length=5;
	iow.IOSer.io_Command=CMD_WRITE;

	DoIO(&iow);

}

static void sendx(void)
{
	UBYTE ctrlx[]={24,3,24,3};

	iow.IOSer.io_Data=ctrlx;
	iow.IOSer.io_Length=4;
	iow.IOSer.io_Command=CMD_WRITE;

	DoIO(&iow);

}

static char *gotfilename, sendfilename[ 256 ];

ALLOCSTATIC( gotfilename, 4096, MEMF_CLEAR )

static ULONG getprotection( char *name )
{
	BPTR lock;
	struct FileInfoBlock *fib;
	ULONG rc = -1;

	lock = Lock( name, SHARED_LOCK );
	if( !lock )
		return( rc );

	fib = allocfib();
	if( fib )
	{
		Examine( lock, fib );
		rc = fib->fib_Protection;
		freefib( fib );
	}

	UnLock( lock );
	return( rc );
}

static int dopackdata(void)
{
	BPTR f,outwin;
	char temp[1024], *p;
	int rc;

	if(!(f=Lock("PUFFER",SHARED_LOCK)))
	{
		strcpy(sendfilename,"CALLER.LHA");
		f=Open(sendfilename,MODE_NEWFILE);
		Write(f,"\r\n",2);
		Close(f);
		return( 0 );
	} else UnLock(f);

/*	sprintf( temp, "CON:40/40/%ld/%ld/Packe Daten.../INACTIVE/AUTO",
		scr->Width - 80,
		scr->Height - 80 ) ;

	if( !isv37 )
		outwin=Open( "CON:40/40/560/110/MicroDot: Packe Daten...", MODE_NEWFILE );
	else
		outwin = OpenCon( temp );*/

	outwin = openconsole( "Packe Daten..." );

	temp[0]=0;
	if(!isv37)
	{
		WBenchToFront();
		sprintf( temp, "cd \"%s\"\n", prefs.transferdir );	
	}

	asprintf(temp,prefs.packer,"caller.lha","PUFFER",0,0,0,0,0,0,0,0,0);

	if( isv37 )
	{
		rc = SystemTags( temp,
			SYS_Input, NULL,
			SYS_Output, outwin,
			NP_StackSize, 16384,
			NP_Cli, TRUE,
			TAG_DONE );
	}
	else
	{
		rc = !Execute(temp,0,outwin);
	}


	DeleteFile( "PUFFER" );
	makefilelist( "", "#?.#?", temp, 1024 );

	p = temp;
	while( *p )
	{
		strcpy( sendfilename, p );
		while( *p++ );

		if( !strnicmp( sendfilename, "BAD-XFER", 8 ) )
			continue;

		if( !( getprotection( sendfilename ) & FIBF_DELETE ) )
			break;
	}

	Close(outwin);

	if(!isv37)
		ScreenToFront(scr);

	return( rc );


}

void setgotfilename( char *txt )
{
	memset( gotfilename, 0, 2048 );
	strcpy( gotfilename, txt );
}

int backdisable;

int unpackdata(void)
{
	BPTR outwin,dirlock;
	struct FileInfoBlock *fib;
	char exec[256];
	ULONG t;
	char x[6];
	char *p = gotfilename;
	int totalarcsize = 0, totalarcs = 0;
	static int destcnt = 0;
	char destdate[ 6 ];

	utunpk( time( 0 ), destdate );

/*	sprintf( exec, "CON:40/40/%ld/%ld/Entpacke Daten.../INACTIVE/AUTO",
		scr->Width - 80 ,
		scr->Height - 80 );

	if( !isv37 )
		outwin=Open( "CON:40/40/560/110/Entpacke Daten...", MODE_NEWFILE );
	else
		outwin = OpenCon( exec );*/

	outwin = openconsole( "Entpacke Daten..." );
	pushdir( prefs.transferdir );

	while( *p )
	{
		int arclen = getfilelen( p );

		totalarcs++;
		totalarcsize += arclen;

		if( arclen < 10 )
		{
			printlog( "Empfangene Archivdatei....: %s (%ld Bytes, deshalb IGNORIERT)\n", p, arclen );
			DeleteFile( p );
			p = strchr( p, 0 ) + 1;
			continue;
		}

		printlog( "Empfangene Archivdatei....: %s (%lD Bytes)\n", p, arclen );

		exec[0] = 0;
		if(!isv37)
		{
			WBenchToFront();
			sprintf( exec, "cd \"%s\"\n", prefs.transferdir );
			asprintf(exec,prefs.unpacker,p,"#?",0,0,0,0,0,0,0,0,0,0);
			Execute(exec,0,outwin);
		}
		else
		{
			int rc;

			sprintf( exec, prefs.unpacker, p, "#?", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );

			rc = SystemTags( exec,
				SYS_Input, NULL,
				SYS_Output, outwin,
				NP_StackSize, 16384,
				NP_Cli, TRUE,
				TAG_DONE 
			);

			if( rc )
			{
				printlog( "Fehler #%ld beim Entpacken (%s)!\n", rc, exec );

				if( !( prefs.flags2 & MDF2_JANUS2 ) )
				{
					Close( outwin );
					popdir();
					return( -1 );
				}
			}
		}

		if( prefs.netcall_save && !backdisable )
		{
			BPTR xdirlock = CreateDir( "BACKUP" );
			UnLock( xdirlock );

			if( prefs.flags2 & MDF2_JANUS2 )
				sprintf( exec, "BACKUP/%s.%ld.%02ld-%02ld-%02ld_%02ld-%02ld-%02ld", prefs.boxname, destcnt++, destdate[ 2 ], destdate[ 1 ], ( destdate[ 0 ] + 70 ) % 100, destdate[ 3 ], destdate[ 4 ], destdate[ 5 ] );
			else
				sprintf( exec, "BACKUP/%s.%02ld-%02ld-%02ld_%02ld-%02ld-%02ld", prefs.boxname, destdate[ 2 ], destdate[ 1 ], ( destdate[ 0 ] + 70 ) % 100, destdate[ 3 ], destdate[ 4 ], destdate[ 5 ] );

			Rename( p, exec );
		}
		else
			DeleteFile( p );

		backdisable = FALSE;

		p = strchr( p, 0 ) + 1;
	}

	printlog( "Insgesamt %lD Archiv-Datei(en), %lD Bytes\n\n", totalarcs, totalarcsize );

	printlog("\nEnthaltene Dateien      Datum/Zeit            Länge in Bytes\n");
	dirlock=Lock("",SHARED_LOCK);
	fib = allocfib();
	Examine( dirlock, fib );
	while( ExNext( dirlock, fib ) )
	{
		if( fib->fib_DirEntryType > 0 )
			continue;
		t=__datecvt(&fib->fib_Date);
		utunpk(t,x);
		printlog( "%-23s %02ld.%02ld.%04ld %02ld:%02ld:%02ld   %lD\n",
			fib->fib_FileName,
			x[2],x[1],x[0]+1970,x[3],x[4],x[5],
			fib->fib_Size);
	}
	freefib( fib );
	UnLock( dirlock );

	popdir();

	Close( outwin );

	if( !isv37 )
		ScreenToFront( scr );

	return( 0 );
}

static int donetcall1( int netcallmode )
{
	int dialnum=prefs.dialretries;
	int c,timeout,doabort=0,connect,isarcing,d,e;
	long ssig,csig,wsig,sigs,tsig;
	char crch,srch,*p; /* console & serial read chars */
	struct IntuiMessage *im;
	int itemnum,showdata;
	long tconnect=0,thangup;
	long sendtime,rectime;
	long sendbytes,recbytes;
	long t;
	int quietsecs;
	char tmp[32];
	char *filearray[2];
	char connectstring[ 32 ];
	int connectlen;
	int allowpw = FALSE;
	char *loginstring = "JANUS";

	if( prefs.flags2 & MDF2_JANUS2 )
	{
		switch( netcallmode )
		{
			case 0:
				loginstring = "JANUS2";
				break;
			case 1:
				loginstring = "JANUS2P";
				break;
			case 2:
				loginstring = "JANUS2N";
				break;
			case 3:
				loginstring = "JANUS2H";
				break;
		}
	}

	/* Pointcfg laden */
	selectmdtprefs( NULL );

	linespeed = prefs.modembaud;

	if(initser( FALSE )) return(-1);
	if(initconsole())
	{
		exitser();
		return(-1);
	}

	SetMenuStrip(twindow,netcallmenustrip);

	sprintf(tmp,"Netcall %s",dat2str(time(0)));
	openlogmsg(tmp);

	printlog("Netcall bei der '%s' am %s\n\n",prefs.boxname,dat2str(time(0)));

	addlogfile( "NETCALL bei %s", prefs.boxname );

	treport(0,1,"Netcall...");
	treport(1,0,"");

	ssig=1<<iorp->mp_SigBit;
	wsig=1<<twindow->UserPort->mp_SigBit;
	csig=1<<crp->mp_SigBit;
	tsig=1<<tport->mp_SigBit;

	cr.io_Data=&crch;
	cr.io_Length=1;
	cr.io_Command=CMD_READ;
	BeginIO( &cr );

	ior.IOSer.io_Data=&srch;
	ior.IOSer.io_Length=1;
	ior.IOSer.io_Command=CMD_READ;
	BeginIO(&ior);

	conprintf("\x1b[0 p\nModem-Initialisierung...\n");
	sendat(prefs.modeminit);
	Delay(24);

	pushdir(prefs.transferdir);
	c=getfilelen("PUFFER"); if(c<2) c=2;
	conprintf("Packe Daten: %lD Bytes",c);
	printlog("Ausgehende Daten ungepackt: %lD Bytes\n",c);

	if( dopackdata() )
	{
		printlog( "Fehler beim Packeraufruf!\n" );
		doabort = 1;
		goto bye;
	}

	sendbytes=d=getfilelen(sendfilename); if(d<1) d=1;
	e = 100-((d*100)/c);
	if( e<0 || e>100) e = 0;
	conprintf(" -> %lD Bytes (%ld%%)\n", d, e);
	printlog("Ausgehende Daten gepackt..: %lD Bytes (%ld%%)\n",d,e);

	ClearPointer( twindow );

	for(c=0; c<dialnum && doabort<2; c++)
	{
		allowpw = FALSE;
		if( c )
		{
			int sq = FALSE;
			int tq = FALSE;

			putrb( 'X' );

			iow.IOSer.io_Command = CMD_CLEAR;
			DoIO( &iow );

			AbortIO( &ior );
			WaitIO( &ior );

			for( d = prefs.retrydelay; d > 0; )
			{
				conprintf("Warte %ld Sekunden... \r",d);

				if( !tq )
				{
					qtimer();
					tq = TRUE;
				}

				if( !sq )
				{
					ior.IOSer.io_Data = &srch;
					ior.IOSer.io_Length = 1;
					ior.IOSer.io_Command = CMD_READ;
					SendIO( &ior );
					sq = TRUE;
				}

				sigs = mWait( csig | wsig | tsig | ssig | SIGBREAKF_CTRL_E );
				if( sigs & wsig )
				{
					im = (struct IntuiMessage *)GetMsg( twindow->UserPort );
					if( im )
						ReplyMsg( im );
					break;
				}

				if( sigs & SIGBREAKF_CTRL_E )
					break;

				if( sigs & csig )
				{
					WaitIO( &cr );
					cr.io_Data=&crch;
					cr.io_Length=1;
					cr.io_Command=CMD_READ;
					SendIO( &cr );
					break;
				}

				if( sigs & tsig )
				{
					WaitIO( &tr );
					tq = FALSE;
					d--;
				}

				if( CheckIO( &ior ) )
				{
					sq = FALSE;
					WaitIO( &ior );
					putrb( srch );
					if( testrb( "RING" ) )
					{
						conprintf( "\n[Eingehender Anruf!]\n" );
						doabort = 2;
						putrb( 'X' );
						break;
					}
				}

				if( !sq )
				{
					ior.IOSer.io_Data = &srch;
					ior.IOSer.io_Length = 1;
					ior.IOSer.io_Command = CMD_READ;
					SendIO( &ior );
					sq = TRUE;
				}
			}

			if( !sq )
			{
				ior.IOSer.io_Data = &srch;
				ior.IOSer.io_Length = 1;
				ior.IOSer.io_Command = CMD_READ;
				SendIO( &ior );
				sq = TRUE;
			}

			if( tq )
			{
				AbortIO( &tr);
				WaitIO( &tr );
				tq = FALSE;
			}
		}

		if( doabort == 2 )
			break;

		connectlen = 0;
		p=getphone(c);
		conprintf("\rAnwahlversuch %ld bei %s; noch %ld Versuche...",c+1,p,dialnum-c-1);
		addlogfile( "NETCALL Wähle %s", p );
		Delay(25);
		iow.IOSer.io_Command = CMD_CLEAR;
		DoIO(&iow);
		sendat( prefs.modemdial );
		sendat( p );
		sendat( "|" );
		timeout=prefs.dialtimeout; connect=0; isarcing=0; doabort=0; showdata=0;
		qtimer();

		quietsecs = 0;

		while( timeout && isarcing != 2 )
		{
			sigs = mWait( ssig | csig | wsig | tsig | SIGBREAKF_CTRL_E );
			if(sigs&wsig) while((im=(struct IntuiMessage*)GetMsg(twindow->UserPort)))
			{
				if(im->Class==IDCMP_MENUHELP) { domenuhelp("netcall",im); ReplyMsg(im); }
				else if( im->Class == IDCMP_CLOSEWINDOW )
				{
					ReplyMsg( im );
					timeout = 0;
					doabort = 2;
				}
				else if( im->Class == IDCMP_NEWSIZE )
				{
					ReplyMsg( im );
					conresize();
				}
				else if( im->Class == IDCMP_REFRESHWINDOW )
				{
					ReplyMsg( im );
					BeginRefresh( w );
					EndRefresh( w, TRUE );
				}
				else if( im->Class == IDCMP_MENUPICK )
				{
					if( !MENUNUM( im->Code ) )
					{
						itemnum=ITEMNUM(im->Code);
						ReplyMsg(im);
						switch(itemnum)
						{
							case 0: timeout=0;
								doabort=1;
								break;
							case 2: timeout=0; doabort=2;
								break;
						}
					}
				}
				else ReplyMsg( im );
			}
			if( CheckIO( &cr ) )
			{
				WaitIO(&cr);
				if(crch==' ') { timeout=0; doabort=1; }
				else if(crch==27) { timeout=0; doabort=2; }
				SendIO(&cr);
			}
			if( sigs & SIGBREAKF_CTRL_E )
			{
				if( !connect )
				{
					timeout = 0;
					doabort = 2;
				}
			}
			if( CheckIO( &ior ) )
			{
				WaitIO( &ior );
				if(showdata==1)
				{
					srch=ibm2iso(srch);
					cw.io_Command=CMD_WRITE;
					cw.io_Data=&srch;
					cw.io_Length=1;
					DoIO(&cw);
				}
				if( connect == 2 )
				{
					connectstring[ connectlen++ ] = srch;
					connectstring[ connectlen ] = 0;
					if( connectlen > 30 || srch == '\n' || srch == '\r' )
					{
						connect = 1;
						linespeed = atoi( connectstring );
					}
				}

				putrb7(srch);
				ior.IOSer.io_Data=&srch;
				ior.IOSer.io_Length=1;
				ior.IOSer.io_Command=CMD_READ;
				BeginIO(&ior);
				quietsecs = 0;
			}

			if( CheckIO( &tr ) )
			{
				/*AbortIO(&tr);*/
				WaitIO(&tr);
				qtimer();
				quietsecs++;
				if( timeout )
					timeout--;
				if(!showdata) conprintf("%02ld:%02ld\x1b[5\x44",TM(timeout),TS(timeout));
			}
			if( connect == 1 )
			{
				if(testrb("nocarrier")) { time(&thangup); connect=0; doabort=2; break; }
				else if( ( quietsecs > 1 ) && ( testrb("username:") || testrb("login:") ) ) { putrb( 0 ); serialclear(); serputs( ISN38 ? "ZERBERUS" : loginstring); showdata=2; conprintf("\rUsername...\n"); }
				else if( ( testrb("systemname:"))) { putrb( 0 ); serputs(prefs.pointname); conprintf("Systemname...\n"); allowpw = TRUE; }
				else if( ( testrb("pressESCtwice"))) { putrb( 0 ); serputs( "\033\033" ); conprintf("Fido-Mailer-Kennung [2xESC] geschickt.\n"); }
				else if( allowpw && ( testrb("passwort:") || testrb("password:"))) { putrb( 0 ); serputs(prefs.password); conprintf("Passwort...\n"); }
				else if(!isarcing && testrb("runningarc")) {
					conprintf("Box packt Daten: ");
					isarcing=1;
					showdata=0;
					timeout=prefs.packtimeout;
				}
				else if(testrb("\x15")) {
					sendzeros();
				}
				else if(testrb("\x6")) {
					long t=prefs.packtimeout-timeout;
					printlog("Packzeit..................: %02ld:%02ld:%02ld\n",
						TH(t),TM(t),TS(t));
					isarcing=2;
				}
				else if( !isarcing && quietsecs > 10 )
				{
					serputs( "" );
				}
			}
			else
			{
				if(testrb("nocarrier") || testrb("nodial") || testrb("diallocked"))
				{
					conprintf("Anwahlversuch gescheitert!\n");
					timeout=0;
					doabort=4;
				}
				else if(testrb("busy"))
				{
					conprintf("Box ist besetzt!\n");
					timeout=0;
					doabort=4;
				}
				else if( testrb( "CONNECT" ) && !connect )
				{
					timeout=prefs.dialtimeout;
					connect=2;
					time(&tconnect);
					printlog( "Benötigte Anwahlversuche..: %ld\n", c + 1 );
					printlog( "Verbindung hergestellt....: %s\n", dat2str( time( 0 ) ) );
					conprintf("Verbindung hergestellt\nLogin...\n");
					conprint("\nCONNECT");
					addlogfile( "NETCALL Verbindung hergestellt" );
					showdata=1;

					if( prefs.flags2 & MDF2_BREAKLOGIN )
					{
						sendx();
						serputs( "" );
					}
				}
			}
		}

		AbortIO(&tr);
		WaitIO(&tr);

		/* Transfer ok? */
		if( isarcing == 2 )
		{
			/* Hydra? */
			if( prefs.pointxfer == 2 )
			{
				int rc;
				struct List hxsl;
				struct tempsendnode {
					struct MinNode n;
					char file[ 128 ];
				} dummy;

				strcpy( dummy.file, sendfilename );
				NewList( &hxsl );
				AddTail( &hxsl, &dummy );

				time( &t );
				AbortIO(&ior);
				WaitIO(&ior);
				AbortIO(&cr);
				WaitIO(&cr);
				download = "";
				rc = hydra_xfer( &hxsl );
				ior.IOSer.io_Data=&srch;
				ior.IOSer.io_Length=1;
				ior.IOSer.io_Command=CMD_READ;
				BeginIO( &ior );
				cr.io_Data=&crch;
				cr.io_Length=1;
				cr.io_Command=CMD_READ;
				BeginIO( &cr );

				sendtime = time( 0 ) - t;
				if( sendtime < 1 )
					sendtime = 1;
				DeleteFile( sendfilename );

				if( rc < 1 )
				{
					conprintf("Transfer fehlgeschlagen!\n\x07");
					printlog("Transfer fehlgeschlagen!\n");
					doabort=2;
				}
				else
				{
					char *p = gotfilename;

					addlogfile( "NETCALL %ld Bytes gesendet (%lds)", sendbytes, sendtime );
					conprintf("ok; %02ld:%02ld:%02ld, %lD cps\n",TH(sendtime),TM(sendtime),TS(sendtime),sendbytes/sendtime);
					makefilelist( "", "#?", gotfilename, 4096 );
					while( *p )
					{
						recbytes = getfilelen( p );
						conprintf("Empfangen: %s, %lD Bytes, %lD cps\n", p, recbytes, recbytes / sendtime );
						addlogfile( "NETCALL %ld Bytes empfangen [%s] (0s)", recbytes, p );
						p = strchr( p, 0 ) + 1;
					}
					doabort=3;
				}
			}
			else
			{
				AbortIO(&ior);
				WaitIO(&ior);
				iow.IOSer.io_Command=CMD_CLEAR;
				DoIO(&iow);
				conprintf("\nSende Daten (%lD Bytes)...",sendbytes);
				time(&t);
				filearray[0]=sendfilename; filearray[1]=NULL;
				setzmodemmode( prefs.pointxfer );
				d=xpr_send(&ior,&iow,-1,filearray);
				sendtime=time(0)-t;
				if(sendtime<1) sendtime=1;
				DeleteFile(sendfilename);
				if(!d)
				{
					conprintf("Senden fehlgeschlagen!\n\x07");
					printlog("Senden fehlgeschlagen!\n");
					doabort=2;
				}
				else
				{
					conprintf("ok; %02ld:%02ld:%02ld, %lD cps\nEmpfange Daten...",TH(sendtime),TM(sendtime),TS(sendtime),sendbytes/sendtime);
					printlog("Sende Daten...............: %lD Byte, %02ld:%02ld:%02ld, %lD cps\n",sendbytes,TH(sendtime),TM(sendtime),TS(sendtime),sendbytes/sendtime);
					addlogfile( "NETCALL %ld Bytes gesendet (%lds)", sendbytes, sendtime );
					strcpy(gotfilename,prefs.transferdir);
					addpart(gotfilename,"called.lzh");
					time(&t);

					d = xpr_receive( &ior, &iow, -1 );
					makefilelist( "", "#?", gotfilename, 4096 );
					rectime = time( 0 ) - t; 
					if( rectime < 1 )
						rectime=1;
					if( !d && !( prefs.flags2 & MDF2_JANUS2 ) )
					{
						if( netcall_resume )
							SetProtection( gotfilename, FIBF_DELETE );

						conprintf("Empfang fehlgeschlagen!\n\x07");
						printlog("Empfang fehlgeschlagen!\n");
						doabort=2;
					}
					else
					{
						char *p = gotfilename;

						doabort = 2;
						while( *p )
						{
							SetProtection( p, 0 );
							recbytes=getfilelen( p );
							conprintf("%s, %lD Bytes, %02ld:%02ld:%02ld, %lD cps\n",
								p, recbytes,TH(rectime),TM(rectime),TS(rectime),recbytes/rectime);
							addlogfile( "NETCALL %ld Bytes empfangen [%s] (%lds)", recbytes, p, rectime );
							printlog("Empfange Daten............: %s, %lD Bytes, %02ld:%02ld:%02ld, %lD cps\n",
								p, recbytes,TH(rectime),TM(rectime),TS(rectime),recbytes/rectime);
							doabort=3;
							p = strchr( p, 0 ) + 1;
						}
					}
				}
			}
			ior.IOSer.io_Command=CMD_CLEAR;
			BeginIO(&ior);
		}
aborting:
		if(doabort && doabort<3)
		{
			if(doabort==2) printlog("Netcall abgebrochen!\n");
			conprintf("abgebrochen!\n");
		}
		if(doabort==4) doabort=1;
		if(!timeout && !doabort) {
			printlog("Timeout!\n");
			conprintf("Timeout!\n");
		}
		
		if(connect)
		{
			conprintf("Auflegen...\n");
			hangup();
			time(&thangup);
		}
		else
			sendat("\r");
	}

	if(tconnect)
	{
		tconnect=thangup-tconnect;
		conprintf("Verbindungsdauer %02ld:%02ld:%02ld\n",TH(tconnect),TM(tconnect),TS(tconnect));
		printlog("Gesamtverbindungsdauer....: %02ld:%02ld:%02ld\n",TH(tconnect),TM(tconnect),TS(tconnect));

		addlogfile( "NETCALL %s (%lds gesamte Verbindungsdauer)",
				( doabort == 3 ) ? "erfolgreich" : "fehlgeschlagen",
				tconnect
		);

	}
	if(doabort==3)
	{
		conprintf("\n\nNetcall erfolgreich beendet.\n");
		printlog("\nNetcall erfolgreich beendet.\n\n");
	}

bye:

	AbortIO(&cr);
	WaitIO(&cr);

	AbortIO(&ior);
	WaitIO(&ior);

	popdir();

	if(doabort==3)
	{
		conprintf("Entpacke Daten...\n");
		if( unpackdata() )
			doabort = 1;
	}
	closelogmsg();

	ClearMenuStrip(twindow);

	exitser();
	exitconsole();

	treport(0,0,""); treport(1,0,"");

	return((doabort==3)?0:-1);
}

static int syscopyfile(char *from,char *to,struct ogwin *ogw, ULONG id)
{
	long len=getfilelen(from);
	BPTR f1,f2;
	void *buffer;
	long blen;
	int rc;
	int fulllen = len;
	int maxbufsize = max( prefs.sm_copybuf * 1024, 1024 );

	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);
	}

	ogreSetMaxVal( ogw, id, len );
	ogreSetValue( ogw, id, 0 );

	blen = min( len, AvailMem( MEMF_LARGEST ) / 2 );
	blen = min( blen, maxbufsize );
	for( ;; )
	{
		buffer = AllocMem( blen, 0 );
		if( buffer )
			break;
		blen /= 2;
	}

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

	FreeMem( buffer, blen );
	Close( f1 );
	Close( f2 );

	return( 0 );
}

static int sysmovefile( char *from, char *to, struct ogwin *ogw, ULONG id )
{
	int rc;

	DeleteFile( to );
	if( Rename( from, to ) )
	{
		ogreSetValue( ogw, id, 1 );
		return( 0 );
	}
	rc = IoErr();
	if( rc != ERROR_RENAME_ACROSS_DEVICES )
		return( rc );
	rc = syscopyfile( from, to, ogw, id );
	if( rc )
		return( rc );
	while( !DeleteFile( from ) )
	{
		rc = IoErr();

		if( rc == ERROR_OBJECT_NOT_FOUND )
			break;
		if( !askreq( "Fehler beim Sysop-Mode-Import: Importdatei\n%s\nkonnte nicht gelöscht werden (%ld)", "Wiederholen|Abbruch", from, rc ) )
			return( ERROR_BREAK );
	}
	return( 0 );
}

static void addtolog( char *file )
{
	char buffer[ 256 ];
	struct AsyncFile *f = OpenAsync( file, MODE_READ, 2048 );

	if( !f )
	{
		printlog( "Datei %s existiert nicht.\n", file );
		return;
	}

	while( FGetsAsync( f, buffer, 256 ) )
	{
		printlog( "%s", buffer );
	}
	CloseAsync( f );
	DeleteFile( file );
}

#ifndef NO_RFC
static int donetcall_rfc( void )
{
	BPTR f = OpenCon( prefs.rfc_cicocon );
	char exec[ 256 ];
	struct DosList *old_uuspool, *old_uulib, *dl;
	BPTR lock;
	int rc;
	char cicofullpath[ 256 ], *p;

	if( !checkprograminpathfull( "UUCICO", cicofullpath ) )
	{
			askreq( "\"UUCICO\" nicht gefunden!\nDas Program \"UUCICO\" muß im Pfad liegen und\naufrufbar sein!", "Abbruch" );
			return( 1 );
	}

	sprintf(exec,"Netcall %s",dat2str(time(0)));
	openlogmsg(exec);
	printlog("Netcall bei der '%s' am %s\n\n",prefs.boxname,dat2str(time(0)));

	dl =  LockDosList( LDF_ASSIGNS | LDF_WRITE );
	old_uuspool = FindDosEntry( dl, "UUSPOOL", LDF_ASSIGNS );
	if( old_uuspool )
		RemDosEntry( old_uuspool );
	old_uulib = FindDosEntry( dl, "UULIB", LDF_ASSIGNS );
	if( old_uulib )
		RemDosEntry( old_uulib );
	UnLockDosList( LDF_ASSIGNS | LDF_WRITE );

	UnLock( CreateDir( "T:mduutmp" ) );
	lock = Lock( "T:mduutmp", SHARED_LOCK );
	AssignLock( "UULIB", lock );
	lock = Lock( prefs.transferdir, SHARED_LOCK );
	AssignLock( "UUSPOOL", lock );

	/* T-Files generieren */
	lock = Open( "UULIB:config", MODE_NEWFILE );
	FPrintf( lock, "NodeName\t%s\nUsername\t%s\nRealname\t%s\nDebug\t5\n",
		prefs.pointname,
		prefs.username,
		prefs.userrealname
	);
	Close( lock );
	lock = Open( "UULIB:L.sys", MODE_NEWFILE );

	// generieren...
	stccpy( exec, prefs.phone, sizeof( exec ) );

	for( p = strtok( exec, "  \t" ); p; p = strtok( NULL, "  \t" ) )
	{
		FPrintf( lock, "%s Any Ser: %ld %s%s %s\n",
			prefs.boxname,
			prefs.modembaud,
			prefs.modemdial,
			p,
			prefs.rfc_login
		);
	}
	Close( lock );

	/* Nun CICO aufrufen */
	sprintf( exec, "%s -D %s -U %ld %s%s%s%s -q -s%s",
		cicofullpath,
		prefs.modemdevice,
		prefs.modemunit,
		prefs.modemflags & 8 ? "-h0 " : "",
		prefs.modemflags & 1 ? "-7 " : "",
		prefs.modem_dropdtr ? "" : "-d0 ",
		prefs.rfc_cicoopts,
		prefs.boxname
	);
	FPrintf( f, "Führe aus: \x1b[1m%s\n\x1b[0m", exec );
	Flush( f );

	rc = SystemTags( exec,
		SYS_Output, f,
		//SYS_Output, NULL,
		NP_StackSize, 32768,
		NP_Priority, 0,
		TAG_DONE
	);
	printlog( "UUCICO-Aufruf: \"%s\", rc = %ld\n", exec, rc );
	printlog( "\nUUCICO-Logfile:\n" );
	addtolog( "UUSPOOL:Logfile" );
	if( exists( "UUSPOOL:Xferlog" ) )
	{
		printlog( "\nUUCICO-Xferlog:\n" );
		addtolog( "UUSPOOL:XferLog" );
	}

	// Temporäre Assigns wieder entfernen

	AssignLock( "UULIB", NULL );
	AssignLock( "UUSPOOL", NULL );

	dl = LockDosList( LDF_ASSIGNS | LDF_WRITE );
	if( old_uuspool )
		AddDosEntry( old_uuspool );
	if( old_uulib )
		AddDosEntry( old_uulib );
	UnLockDosList( LDF_ASSIGNS | LDF_WRITE );

	SystemTags( "DELETE >NIL: T:mduutmp ALL QUIET", TAG_DONE );

	Close( f );
	closelogmsg();

	return( 0 );
}

#endif

#define IID_STATUS 1
#define IID_ACT 2
#define IID_FUEL 3

#if 0
#define AMITCP_NEW_NAMES
#define openlog foobaryx
#include <netinclude:sys/types.h>
#include <netinclude:sys/socket.h>
#include <netinclude:bsdsocket.h>
#include <netinclude:netinet/in.h>
#include <netinclude:netdb.h>
#include <constructor.h>
struct Library *SocketBase;

CONSTRUCTOR_P(opensock,15000)
{
	SocketBase = OldOpenLibrary( "bsdsocket.library" );
	return( 0 );
}
DESTRUCTOR_P(closesock,15000)
{
	if( SocketBase )
		CloseLibrary( SocketBase );
}

static int clipsaug( void )
{
	BPTR fh = Open( "CON:50/20/400/180/CLIPSAUG-Transfer/AUTO/WAIT/CLOSE/SCREEN*", MODE_NEWFILE );
	int sock;
	struct hostent *host;
	static struct sockaddr_in sockadr;
	struct loginpkt {
		char pointname[ 32 ];
		char password[ 28 ];
		ULONG bytes;
	} loginpkt;
	struct AsyncFile *f;
	char buffer[ 2048 ];
	int len, rlen;

	FPrintf( fh, "CLIPSaug bei %s...\n", prefs.phone );

	strcpy( loginpkt.pointname, prefs.pointname );
	strcpy( loginpkt.password, prefs.password );

	host = GetHostByName( prefs.phone );
	if( !host )
	{
		FPrintf( fh, "Server-Adresse nicht auffindbar\n" );
		Close( fh );
		return( -1 );
	}

	sock = Socket( AF_INET, SOCK_STREAM, 0 );
	if( sock < 0 )
	{
		FPrintf( fh, "Socket konnte nicht erzeugt werden (%ld)!\n", Errno() );
		Close( fh );
		return( -1 );
	}

	sockadr.sin_len = sizeof( sockadr );
	memcpy( &sockadr.sin_addr, *host->h_addr_list, 4 );
	sockadr.sin_family = AF_INET;
	sockadr.sin_port = 5557;

	if( Connect( sock, &sockadr, sizeof( sockadr ) ) )
	{
		FPrintf( fh, "Connection failed! (%ld)\n", Errno() );
		CloseSocket( sock );
		Close( fh );
		return( -1 );
	}

	// Verbindung besteht, nun loginpkt schicken
	pushdir( prefs.transferdir );
	loginpkt.bytes = getfilelen( "PUFFER" );
	if( loginpkt.bytes < 0 )
		loginpkt.bytes = 0;
	FPrintf( fh, "Sende LoginPKT...\n" );
	Send( sock, &loginpkt, sizeof( loginpkt ), 0 );

	if( len = loginpkt.bytes )
	{
		f = OpenAsync( "PUFFER", MODE_READ, 16384 );
		while( loginpkt.bytes )
		{
			int rc = ReadAsync( f, buffer, 2048 );
			int rc2 = Send( sock, buffer, rc, 0 );
			if( rc != rc2 )
			{
				FPrintf( fh, "Fehler beim Senden!\n" );
				CloseAsync( f );
				CloseSocket( sock );
				Close( fh );
				popdir();
				return( -1 );	
			}
			loginpkt.bytes -= rc;
			FPrintf( fh, "Sende: %ld/%ld Bytes\r", len - loginpkt.bytes, len );
		}
		CloseAsync( f );
		DeleteFile( "PUFFER" );
		FPrintf( fh, "\nSenden erfolgreich abgeschlossen.\n" );
	}

	FPrintf( fh, "Warte auf Empfang...\n" );
	if( Recv( sock, &len, 4, 0 ) != 4 )
	{
		FPrintf( fh, "Fehler beim Handshake!\n" );
		CloseSocket( sock );
		Close( fh );
		popdir();
		return( -1 );	

	}
	FPrintf( fh, "Empfange %ld Bytes\n", len );

	if( len )
	{
		f = OpenAsync( "CALLED.LZH", MODE_WRITE, 16384 );
		rlen = len;
		while( len )
		{
			int rc = Recv( sock, buffer, 2048, 0 );
			if( rc <= 0 )
			{
				FPrintf( fh, "Fehler beim Empfangen!\n" );
				CloseAsync( f );
				CloseSocket( sock );
				Close( fh );
				popdir();
				return( -1 );	
			}
			WriteAsync( f, buffer, rc );
			len -= rc;
			FPrintf( fh, "Empfange: %ld/%ld Bytes\r", rlen - len, rlen );
		}
		CloseAsync( f );
	}
	FPrintf( fh, "\nCLIPSaug erfolgreich beendet.\n" );
	CloseSocket( sock );
	popdir();
	unpackdata();
	Close( fh );
	return( 0 );
}
#endif

int donetcall( int mode )
{
	int rc;
	char path[256];
	struct ogwin *ogw;
	struct Window *iw;

#if 0
	if( prefs.flags2 & MDF2_CLIPSAUG )
	{
		return( clipsaug() );
	}
#endif

	if(!(prefs.flags&MDF_SYSOPMODE))
	{
#ifndef NO_RFC
		if( prefs.mode == MDM_RFC )
		{
			return( donetcall_rfc() );
		}
		else
		{
#endif
			return( donetcall1( mode ) );
#ifndef NO_RFC
		}
#endif
	}

	addlogfile( "SYSOPMODENETCALL für %s", prefs.boxname );

	ogw = ogreInitWindow( scr, WFLG_RMBTRAP, 0, "Sysop-Modus Datenaustausch" );
	ogreAddGroup( ogw, 0, OGFRAME_NONE, NULL );
	ogreAddText( ogw, 0, "Status:", IID_STATUS, "", 40, 1 );
	ogreAddText( ogw, 1, "Aktion:", IID_ACT, "", 40, 1 );
	ogreAddFuelGauge( ogw, 2, IID_FUEL, 1 );
	iw = ogreOpenWindow( ogw );
	if( !iw )
		return( 0 );

	ogreSetStringValue( ogw, IID_ACT, "Führe Init-Befehle aus" );
	system( prefs.sm_init );

	pushdir( prefs.transferdir );
	if( ( rc = getfilelen("PUFFER") ) > 2 )
	{
		sprintf( path, "Exportiere Daten... (%lD Bytes)", rc );
		addlogfile( "SYSOPMODENETCALL %ld Bytes exportiert", rc );
		ogreSetStringValue( ogw, IID_STATUS, path );
		sprintf( path, prefs.sm_exportfile, prefs.counter++, 0, 0, 0, 0, 0, 0, 0 );
		if( prefs.sm_exportbefore[0] )
		{
			ogreSetStringValue( ogw, IID_ACT, "Führe Preexport-Befehle aus" );
			system( prefs.sm_exportbefore );
		}
		ogreSetStringValue( ogw, IID_ACT, "Kopiere Daten..." );
		rc = sysmovefile( "PUFFER", path, ogw, IID_FUEL );
		if( rc )
		{
			askreq( "Export fehlgeschlagen!\nFehler Nr. %ld (%s)",
				"Abbruch",
				rc,
				errorstring( rc )
			);
			popdir();
			ogreExitWindow( ogw );
			return( -1 );
		}

		if( prefs.sm_exportafter[0] )
		{
			ogreSetStringValue( ogw, IID_ACT, "Führe Postexport-Befehle aus" );
			system( prefs.sm_exportafter );
		}
	}
	DeleteFile("PUFFER");
	if(prefs.sm_importbefore[0])
	{
		ogreSetStringValue( ogw, IID_ACT, "Führe Preimport-Befehle aus" );
		system(prefs.sm_importbefore);
	}
	rc=getfilelen(prefs.sm_importfile);
	if(rc>2) {
		sprintf( path, "Importiere Daten (%lD Bytes)", rc );
		addlogfile( "SYSOPMODENETCALL %ld Bytes importiert", rc );
		ogreSetStringValue( ogw, IID_STATUS, path );
		ogreSetStringValue( ogw, IID_ACT, "Kopiere Daten..." );
		sysmovefile(prefs.sm_importfile,"sysop_modus.import",ogw, IID_FUEL);
	}

	if(prefs.sm_importafter[0])
	{
		ogreSetStringValue( ogw, IID_ACT, "Führe Postimport-Befehle aus" );
		system(prefs.sm_importafter);
	}

	popdir();

	ogreExitWindow( ogw );

	return(0);
}
