#include <libraries/zbbs.h>
#include "protos.h"
#include "globals.c"

VOID ShowFile(STRPTR, ...);
VOID CheckMenu(VOID);
VOID Clock(VOID);
STRPTR instr(STRPTR, STRPTR);
WORD __stdargs MyEasyRequest(UBYTE *, UBYTE *, ...);
VOID HandleRexx(VOID);
VOID wprintf(struct RastPort *, UWORD, UWORD, UBYTE *, ...);
VOID In(LONG, LONG);
VOID BlockWindow(struct Window *);
VOID ReleaseWindow(struct Window *);
struct Protocol *GetProtocol(LONG);
VOID ShowSystem(VOID);

VOID QueueTimer()
{
	DoTime->tr_time.tv_micro	= 0;
	DoTime->tr_time.tv_secs		= 1;

	SendIO(DoTime);
}

VOID QueueConsole()
{
	ReadCON->io_Command	= CMD_READ;
	ReadCON->io_Data		= console_in;
	ReadCON->io_Length	= 1;

	SendIO(ReadCON);
}

VOID QueueSerial()
{
	ReadSER->IOSer.io_Command	=	CMD_READ;
	ReadSER->IOSer.io_Data		=	serial_in;
	ReadSER->IOSer.io_Length	=	1;

	SendIO(ReadSER);
}

VOID Send()
{
	STRPTR ptr;

	if(User.amiga)
	{
		while(ptr = strchr(out_buffer, 132))	*ptr = 'ä';
		while(ptr = strchr(out_buffer, 148))	*ptr = 'ö';
		while(ptr = strchr(out_buffer, 129))	*ptr = 'ü';
		while(ptr = strchr(out_buffer, 142))	*ptr = 'Ä';
		while(ptr = strchr(out_buffer, 153))	*ptr = 'Ö';
		while(ptr = strchr(out_buffer, 154))	*ptr = 'Ü';
		while(ptr = strchr(out_buffer, 225))	*ptr = 'ß';
	}
	else
	{
		while(ptr = strchr(out_buffer, 228))	*ptr = '„';
		while(ptr = strchr(out_buffer, 246))	*ptr = '”';
		while(ptr = strchr(out_buffer, 252))	*ptr = '';
		while(ptr = strchr(out_buffer, 196))	*ptr = 'Ž';
		while(ptr = strchr(out_buffer, 214))	*ptr = '™';
		while(ptr = strchr(out_buffer, 220))	*ptr = 'š';
		while(ptr = strchr(out_buffer, 223))	*ptr = 'á';
	}

	if(Status.window > 0)
	{
		WriteCON->io_Command	= CMD_WRITE;
		WriteCON->io_Data		= out_buffer;
		WriteCON->io_Length	= -1;
		WriteCON->io_Flags	= IOF_QUICK;
		DoIO(WriteCON);
	}
	if(ser_out)
	{
		WriteSER->IOSer.io_Command	= CMD_WRITE;
		WriteSER->IOSer.io_Data		= out_buffer;
		WriteSER->IOSer.io_Length	= strlen(out_buffer);
		WriteSER->IOSer.io_Flags	= IOF_QUICK;
		DoIO(WriteSER);
	}
	if(FH_Capture)	Write(FH_Capture, out_buffer, strlen(out_buffer));
	if(FH_Printer)	Write(FH_Printer, out_buffer, strlen(out_buffer));
}

VOID Char(UBYTE c)
{
	out_buffer[0] = c;
	out_buffer[1] = 0;
	Send();
}

VOID MyPrintf(UBYTE *string, ...)
{
	VSPrintf(out_buffer, string, (STRPTR)(&string + 1));
	Send();
}

VOID Csi(char c)
{
	MyPrintf("%lc[%lc", ESC, c);
}

VOID Return()
{
	MyPrintf("\r\n");
}

VOID Backspace()
{
	MyPrintf("%lc %lc", BACK_SPACE, BACK_SPACE);
}

VOID color(LONG color)
{
	if(ansi > 1)	MyPrintf(Config.ansi_colors[color]);
}

VOID gotoxy(LONG x, LONG y)
{
	if(ansi == 1)
		MyPrintf("\33Y%ld%ld", y, x);
	else
		MyPrintf("\33[%ld;%ldH", y, x);
}

VOID ClrScr()
{
	if(User.screenblank)
	{
		if(ansi > 1)
			MyPrintf("\33[1;1H\33[2J\33[1;1H");
		else
			Char(FORM_FEED);
	}
}

VOID RemLine(STRPTR line)
{
	LONG i;

	i = strlen(line);
	SPrintf(out_buffer, "%lc %lc", BACK_SPACE, BACK_SPACE);
	while(i--)	Send();
}

VOID Ask(STRPTR string, STRPTR pre, LONG chars, BOOL cr, ...)
{
	char prompt[81];

	VSPrintf(prompt, string, (STRPTR)(&string + 4));

	color(CYAN);
	MyPrintf(prompt);

	color(GREEN);
	if(pre)	strcpy(wait_buffer, pre);
	In((chars > 0 ? chars : 79 - strlen(prompt)), (pre ? 4 : 3));

	if(cr)	Return();
	else
	{
		if(!pre)
		{
			RemLine(wait_buffer);
			RemLine(prompt);
		}
	}
}

VOID WaitKey()
{
	MyPrintf("Drücke eine Taste ...");
	In(1, 1);
	Return();
}

VOID ClearDevs()
{
	while(CheckIO(ReadCON))
	{
		WaitIO(ReadCON);
		QueueConsole();
	}
	while(CheckIO(ReadSER))
	{
		WaitIO(ReadSER);
		QueueSerial();
	}
}

VOID Beep()
{
	BOOL win_temp;

	win_temp = Status.window;
	Status.window = FALSE;
	Char(BELL);
	Status.window = win_temp;

	DoAudio->ioa_Period = 300;
	DoAudio->ioa_Cycles = 150;
	BeginIO((struct IORequest *)DoAudio);
	WaitIO(DoAudio);
}

VOID Bell()
{
	COUNT i;
	BOOL win_temp;

	win_temp = Status.window;
	Status.window = FALSE;
	Char(BELL);
	Status.window = win_temp;

	i = 0;
	while(i++ < 10)
	{
		DoAudio->ioa_Period = 500;
		DoAudio->ioa_Cycles = 30;
		BeginIO((struct IORequest *)DoAudio);
		WaitIO(DoAudio);

		DoAudio->ioa_Period = 1000;
		DoAudio->ioa_Cycles = 20;
		BeginIO((struct IORequest *)DoAudio);
		WaitIO(DoAudio);
	}
}

VOID GetDate()
{
	DateStamp(&date_time.dat_Stamp);
	DateToStr(&date_time);

	CurrentTime(&time_now, &micros);
}

VOID Location(STRPTR where)
{
	char file[256];
	BPTR FH;

	GetDate();

	SetDrMd(Win2->RPort, JAM1);
	SetAPen(Win2->RPort, 0);
	RectFill(Win2->RPort, 0, 53, 496, 61);
	SetAPen(Win2->RPort, 6 - (depth == 1));
	wprintf(Win2->RPort, 3, 53, "Location: %.52ls", where);

	SPrintf(file, "%lsLogfile", Config.log);
	if(FH = COpen(file))
	{
		Seek(FH, 0, OFFSET_END);
		SPrintf(file, "%ls  %.200ls\n", time, where);
		Write(FH, file, strlen(file));
		Close(FH);
	}
	else
	{
		color(BLINK);
		color(RED);
		MyPrintf("\r\nERROR in Location(): couldn't open/create logfile !\r\n");
		color(NORMAL);
	}
}

VOID SendError_old(STRPTR routine, STRPTR string, ...)
{
	Return();
	color(BLINK);
	color(RED);
	SPrintf(out_buffer, "ERROR in %ls(): ", routine);
	VSPrintf(&out_buffer[strlen(out_buffer)], string, (STRPTR)(&string + 1));
	Send();
	Location(out_buffer);
	color(NORMAL);
	Return();

	Beep();
	Beep();
}

STRPTR instr(STRPTR s1, STRPTR i1)
{
	STRPTR s2, i2, ret;

	ret = NULL;

	if(s2 = AllocVec(strlen(s1) + 1, MEMF_ANY))
	{
		if(i2 = AllocVec(strlen(i1) + 1, MEMF_ANY))
		{
			CopyMem(s1, s2, strlen(s1) + 1);
			CopyMem(i1, i2, strlen(i1) + 1);

			strupr(s2);
			strupr(i2);

			ret = strstr(s2, i2);

			FreeVec(i2);
		}
		FreeVec(s2);
	}

	return(ret);
}

LONG doremote(char c, LONG buff_pos, LONG len, LONG how)
{
	switch(c)
	{
		case BACK_SPACE:
			if(len == 1)
			{
				wait_buffer[buff_pos++] = c;
			}
			else
			{
				if(buff_pos > 0)
				{
					if(how != 1)	Backspace();
					buff_pos--;
				}
				else	Beep();
			}
			break;

		case LINE_FEED:
		case CTRL_X:
			buff_pos = 0;
			break;

		default:
			if(buff_pos < len && (how == 1 || !iscntrl(c)))
			{
				if(how == 0)				c = toupper(c);
				if(how == 0 || how > 2)	Char(c);
				if(how == 2)				Char('*');

				wait_buffer[buff_pos++] = c;
			}
			break;
	}
	return(buff_pos);
}

/*
how :	1 = keine Mitschrift
		2 = ****
		3 = Gross und Klein
		4 =   "    "    "   & text uebergeben & zurueck bei Zeilenende
*/

VOID In(LONG len, LONG how)
{
	BOOL stop;
	LONG i, buff_pos;
	ULONG waitmask;

	if(how == 4 && strlen(wait_buffer))
	{
		buff_pos = strlen(wait_buffer);
		if(buff_pos >= len)
			buff_pos = 0;
		else
			MyPrintf("%ls", wait_buffer);
	}
	else
	{
		i = strlen(wait_buffer);
		while(i--)	wait_buffer[i] = 0;
		buff_pos = 0;
	}

	stop = FALSE;
	do
	{
		waitmask = Wait((1L << Win1->UserPort->mp_SigBit) |
							(1L << Win2->UserPort->mp_SigBit) |
							(1L << ReadPortCON->mp_SigBit) |
							(1L << ReadPortSER->mp_SigBit) |
							(1L << DoTime->tr_node.io_Message.mn_ReplyPort->mp_SigBit) |
							(1L << RexxPort->mp_SigBit));

		if(waitmask & (1L << DoTime->tr_node.io_Message.mn_ReplyPort->mp_SigBit))
		{
			if(CheckIO((struct IORequest *)DoTime))
			{
				QueueTimer();
				Clock();

				Status.time_on += (time_now - time_last);
				if(connected || login)
				{
					User.time_used += (time_now - time_last);
					Status.online_today += (time_now - time_last);
					Status.online += (time_now - time_last);
					if(connected || login && User.level)
					{
						if(User.time < User.time_used)
						{
							color(RED);
							MyPrintf("\r\nSorry, deine Systemzeit ist fuer heute abgelaufen.\r\n\r\n");
							Beep();	Beep();	Beep();
							HangUp();
							stop = TRUE;
							warnung = 4;
						}
						if((User.time - User.time_used) < 60 && warnung < 3)
						{
							color(RED);
							MyPrintf("\r\nAchtung : Du hast nur noch 1 min Systemzeit, danach logoff !!!\r\n\r\n");
							Beep();	Beep();
							warnung = 3;
						}
						if((User.time - User.time_used) < 300 && warnung < 2)
						{
							color(RED);
							MyPrintf("\r\nAchtung : Du hast nur noch 5 min Systemzeit !!\r\n\r\n");
							Beep();
							warnung = 2;
						}
						if((User.time - User.time_used) < 600 && !warnung)
						{
							color(RED);
							MyPrintf("\r\nAchtung : Du hast noch 10 min Systemzeit !\r\n\r\n");
							Beep();
							warnung = 1;
						}
					}
				}
				time_last = time_now;
			}
		}

		if(waitmask & (1L << ReadPortCON->mp_SigBit))
		{
			if(CheckIO(ReadCON))
			{
				WaitIO(ReadCON);
				if(keyboard)
				{
					if(console_in[0] == '\r')	stop = TRUE;
					if(!stop)	buff_pos = doremote(console_in[0], buff_pos, len, how);
				}
				QueueConsole();
			}
		}

		if(waitmask & (1L << ReadPortSER->mp_SigBit))
		{
			if(CheckIO(ReadSER))
			{
				WaitIO(ReadSER);
				if(ser_in)
				{
					if(serial_in[0] == '\r')	stop = TRUE;
					if(!stop)	buff_pos = doremote(serial_in[0], buff_pos, len, how);
				}
				QueueSerial();
			}
		}

		if(waitmask & (1 << RexxPort->mp_SigBit))
		{
			while(rx_msg = GetMsg(RexxPort))
				HandleRexx();
		}

		if((len == 1 && buff_pos == 1) || ((how == 4  || how == 1) && buff_pos >= len))
			stop = TRUE;

		if(!stop)
		{
			stop = (connected || login);

			CheckMenu();

			if(!CarrierSet() && connected)	HangUp();
			if(stop != (connected || login)) stop = TRUE;
			else	stop = FALSE;
		}
	}	while(!stop);

	wait_buffer[buff_pos] = 0;
}

BOOL GetFReq(STRPTR title, STRPTR file, BOOL save, BOOL multi, BOOL list)
{
	LONG i;

	BlockWindow(Win1);
	BlockWindow(Win2);

	if(AslRequestTags(AslFileRequest,
		ASL_Window, Win1,
		ASL_File, file,
		ASL_Dir, asl_path,
		ASL_Hail, title,
		ASL_FuncFlags, (save ? FILF_SAVE : NULL) | (multi ? FILF_MULTISELECT : NULL),
		TAG_DONE))
	{
		strcpy(asl_path, AslFileRequest->rf_Dir);
		if(file)	strcpy(file, AslFileRequest->rf_File);
		if(list)
		{
			struct Line *entry;

			RemList(&FileList);
			if(AslFileRequest->rf_NumArgs)
			{
				i = 0;
				while(i < AslFileRequest->rf_NumArgs)
				{
					if(entry = GetLine())
					{
						strcpy(entry->text, AslFileRequest->rf_ArgList[i].wa_Name);
						AddTail(&FileList, entry);
					}
					i++;
				}
			}
			else
			{
				if(entry = GetLine())
				{
					strcpy(entry->text, AslFileRequest->rf_File);
					AddTail(&FileList, entry);
				}
			}
		}

		ReleaseWindow(Win1);
		ReleaseWindow(Win2);

		return(TRUE);
	}

	ReleaseWindow(Win1);
	ReleaseWindow(Win2);

	return(FALSE);
}


LONG GetPReq()
{
	struct Window		*ProtWin;
	struct Protocol	*entry;
	struct Gadget		*Gadgets[2], *g, *glist;
	struct NewGadget	ng;
	struct IntuiMessage *imsg;
	LONG sec1, sec2, mic1, mic2, i, protocol;
	ULONG code, class;

	protocol = Status.protocol;

	if(!(ProtWin = OpenWindowTags( NULL,
		WA_Width,			210,
		WA_Height,			100,
		WA_Top,				Scr->Height / 2 - 50,
		WA_Left,				Scr->Width / 2 - 105,
		WA_SmartRefresh,	TRUE,
		WA_CustomScreen,	Scr,
		WA_Activate,		TRUE,
		WA_DepthGadget,	TRUE,
		WA_CloseGadget,	TRUE,
		WA_DragBar,			TRUE,
		WA_CustomScreen,	Scr,
		WA_Title,			"select protocol...",
		WA_IDCMP, 			BUTTONIDCMP | IDCMP_CLOSEWINDOW | SLIDERIDCMP | LISTVIEWIDCMP ,
		TAG_DONE )))	return(protocol);

	if(!(g = CreateContext(&glist)))
	{
		CloseWindow(ProtWin);
		return(protocol);
	}

	ng.ng_LeftEdge		= 10;
	ng.ng_TopEdge		= 15;
	ng.ng_Width			= 190;
	ng.ng_Height		= 80;
	ng.ng_GadgetText	= NULL;
	ng.ng_TextAttr		= &FontAttr,
	ng.ng_GadgetID		= 0;
	ng.ng_VisualInfo	= VisualInfo;

	Gadgets[0] =
	g = CreateGadget( LISTVIEW_KIND, g, &ng,
		GTLV_Labels,			&ProtocolList,
		GTLV_ShowSelected,	NULL,
		GTLV_ScrollWidth,		20,
		TAG_DONE );

	if(!g)
	{
		FreeGadgets(glist);
		CloseWindow(ProtWin);
		return(protocol);
	}

	AddGList(ProtWin, glist, 0, -1, NULL);
	RefreshGList(glist, ProtWin, NULL, -1);
	GT_RefreshWindow(ProtWin, NULL);
	GT_SetGadgetAttrs(Gadgets[0], ProtWin, NULL,
		GTLV_Selected,	protocol - 1,
		TAG_END);

	BlockWindow(Win1);
	BlockWindow(Win2);

	CurrentTime(&sec1, &mic1);
	while(TRUE)
	{
		Wait(1L << ProtWin->UserPort->mp_SigBit);

		while(imsg = GT_GetIMsg(ProtWin->UserPort))
		{
			class	= imsg->Class;
			code	= imsg->Code;
			g		= imsg->IAddress;

			GT_ReplyIMsg(imsg);

			if(class == IDCMP_GADGETUP)
			{
				switch(g->GadgetID)
				{
					case 0:
						i = code;
						entry = GetHead(&ProtocolList);
						while(i-- && entry)	entry = GetSucc(entry);

						CurrentTime(&sec2, &mic2);
						if(DoubleClick(sec1, mic1, sec2, mic2) && protocol == code + 1)
							goto bibi;
						else
						{
							protocol = code + 1;
							sec1 = sec2;
							mic1 = mic2;
						}
						break;
				}
			}
			if(class == IDCMP_CLOSEWINDOW)	goto bibi;
		}
	}
bibi:
	if(glist)
	{
		RemoveGList(ProtWin, glist, -1);
		FreeGadgets(glist);
	}
	if(ProtWin)	CloseWindow(ProtWin);

	ReleaseWindow(Win1);
	ReleaseWindow(Win2);

	return(protocol);
}

VOID CheckMenu()
{
	struct IntuiMessage *message;
	ULONG class, code, i;

	while(message = GetMsg(Win1->UserPort))
	{
		class	= message->Class;
		code	= message->Code;
		ReplyMsg(message);

		if(class == IDCMP_MENUPICK)
		{
			struct MenuItem *item;

			while(code != MENUNULL)
			{
				item = ItemAddress(menu, code);

				switch((ULONG)MENU_USERDATA(item))
				{
					case MEN_PALETTE:
						Palette();
						break;

					case MEN_CHAT:
						chat = !chat;
						if(chat)	Chat();
						break;

					case MEN_LOGIN:
						login = !login;
						break;

					case MEN_BUSY:
						ATCmd(Config.busy);
						break;

					case MEN_HANGUP:
						HangUp();
						break;

					case MEN_QUIT:
					{
						char file[256];

						SPrintf(file, "%lsStatus", Config.system);
						RefreshStatus(file, &Status);
						error(NULL);
					}
						break;


					case MEN_SYSOP:
						Status.sysop = !Status.sysop;
						break;

					case MEN_WINDOW:
						if(Status.window != -1)	Status.window = !Status.window;	
						break;

					case MEN_KEYBOARD:
						keyboard = !keyboard;
						break;

					case MEN_INPUT:
						ser_in = !ser_in;
						break;

					case MEN_OUTPUT:
						ser_out = !ser_out;
						break;

					case MEN_CAPTURE:
						if(FH_Capture)
						{
							Close(FH_Capture);
							FH_Capture = NULL;
						}
						else
						{
							char file[256];

							SPrintf(file, "%ls%ls.capture", Config.capture, User.alias);
							if(FH_Capture = COpen(file))
							{
								Seek(FH_Capture, 0, OFFSET_END);
								SPrintf(file, "\n------------------------\nCapture opened on %ls %ls\n\n", date, time);
								Write(FH_Capture, file, strlen(file));
								Beep();
							}
							else	SendError("CheckMenu", "Konnte Captur nicht öffnen");
						}
						break;

					case MEN_PRINTER:
						if(FH_Printer)
						{
							Close(FH_Printer);
							FH_Printer = NULL;
						}
						else
						{
							if(FH_Printer = COpen("PRT:"))
							{
								FPrintf(FH_Printer, "Capture opened on %ls %ls\nUser : %ls %ls [%ls]", date, time, User.first_name, User.name, User.alias);
								Beep();
							}
							else	SendError("CheckMenu", "Konnte Printer nicht ansprechen");
						}
						break;

					case MEN_PLUS:
						User.time_used -= (User.time_used > 599 ? 600 : 0);
						break;

					case MEN_MINUS:
						User.time_used += 600;
						break;

					case MEN_ATA:
						ATCmd(Config.answer);
						break;

					case MEN_TERMINAL:
						term = !term;
						if(term)	Terminal();
						break;

					case MEN_SEND:
						if(GetFReq("Wähle File(s) aus...", NULL, FALSE, TRUE, TRUE)) /* file, save, multi, list */
						{
							struct Protocol *protocol;

							protocol = GetProtocol(Status.protocol ? Status.protocol : 1);
							ser_out = FALSE;
							DoTransfer(asl_path, protocol, TRUE);
							ser_out = TRUE;
						}
						break;

					case MEN_RECEIVE:
						if(TRUE)
						{
							struct Protocol *protocol;
							BOOL doit;

							protocol = GetProtocol(Status.protocol ? Status.protocol : 1);
							if(protocol && !protocol->batch)
								doit = GetFReq("Wähle Filenamen und Directory", NULL, FALSE, FALSE, TRUE); /* file, save, multi, list*/
							else
								doit = GetFReq("Wähle Directory...", NULL, TRUE, FALSE, FALSE); /* file, save, multi, list*/

							ser_out = FALSE;
							if(doit)	DoTransfer(asl_path, protocol, FALSE);
							ser_out = TRUE;
						}
						break;

					case MEN_PROTOCOL:
						Status.protocol = GetPReq();
						break;

					case MEN_ASCII:
						if(GetFReq("Wähle ASCII-File(s)...", NULL, FALSE, TRUE, TRUE)) /* file, save, multi, list*/
						{
							struct Line *line;

							line = GetHead(&FileList);
							while(line)
							{
								ShowFile("%ls%ls", asl_path, line->text);
								line = GetSucc(line);
							}
							RemList(&FileList);
						}
						break;

					default:
						i = (ULONG)MENU_USERDATA(item) - MEN_USER1;
						if(i >= 0 && i < 10)
						{
							struct Line *line;

							line = GetHead(&MenuList);
							line = GetSucc(line);

							while(line && i--)
							{
								line = GetSucc(line);
								line = GetSucc(line);
							}
							if(line && i == -1)	ShowPrg(line->text);
						}
				}
				code = item->NextSelect;
			}
		}
	}
	while(message = GetMsg(Win2->UserPort))
	{
		class	= message->Class;
		code	= message->Code;
		ReplyMsg(message);

		if(class == ACTIVEWINDOW)	ActivateWindow(Win1);
	}
}

VOID ShowFile(UBYTE *name, ...)
{
	STRPTR ptr, buffer, buf;
	char file[256];
	LONG stop, line, mail_line, size;
	BOOL mail, quote;

	line = 0;
	mail = FALSE;
	quote = FALSE;
	VSPrintf(file, name, (STRPTR)(&name + 1));

	if(Compare(&file[strlen(file) - 4], ".txt") && ansi > 1)
	{
		strcpy(&file[strlen(file) - 3], "ansi");
		if(!Exists(file))	strcpy(&file[strlen(file) - 4], "txt");
	}

	if(Compare(&file[strlen(file) - 2], ".i"))
	{
		file[strlen(file) - 2] = 0;
		if(User.partial_scroll)	mail = TRUE;
		else	line = 4;
	}

	if(!(buffer = GetFile(file, &size)))	return;

	buf = buffer;
	stop = (User.lines < 1 ? -1 : FALSE);
	mail_line = (User.lines < 1 ? 22 : User.lines - 1);
	color(WHITE);
	ClearDevs();

	do
	{
		if(mail)
		{
			if(buf[0] == '>' || buf[1] == '>' || buf[2] == '>' || 
				buf[3] == '>')
			{
				if(!quote)
				{
					quote = TRUE;
					color(GREEN);
				}
			}
			else
			{
				if(quote)
				{
					quote = FALSE;
					color(WHITE);
				}
			}
			Csi(DEL_RO_LINE);
		}

		ptr = strchr(buf, '\n');
		if((ptr - buf) > 1000 || !ptr)
		{
			MyPrintf("%.1000ls", buf);
			buf += 1000;
		}
		else
		{
			*ptr = 0;
			MyPrintf("%ls\r\n", buf);
			buf = ptr + 1;
			line++;
		}

		if(CheckIO(ReadCON))
		{
			WaitIO(ReadCON);
			if(keyboard)
			{
				buf = buffer + size;
				MyPrintf("<Abbruch>\r\n");
			}
			QueueConsole();
		}

		if(CheckIO(ReadSER))
		{
			WaitIO(ReadSER);
			if(serial_in)
			{
				buf = buffer + size;
				MyPrintf("<Abbruch>\r\n");
			}
			QueueSerial();
		}

		CheckMenu();

		if(!stop && (line > (User.lines - 2 - (mail * 4))))
			stop = TRUE;

		if(stop > 0 && buf < buffer + size)
		{
			SPrintf(file, "More (%ld%%) [Y/n/c]", (buf - buffer) * 100 / size);
			Ask(file, NULL, HOTKEY, FALSE);
			if(!connected && !login)
			{
				FreeVec(buffer);
				return;
			}
			stop = FALSE;
			if(toupper(wait_buffer[0]) == 'N')	stop = TRUE;
			if(toupper(wait_buffer[0]) == 'C')	stop = -1;

			color(WHITE);
			line = 0;
			if(mail && toupper(wait_buffer[0]) != 'N')
			{
				MyPrintf("\33[5;1H");
			}
			quote = FALSE;
		}

		if(!CarrierSet() && connected && !login)	HangUp();

	}	while((buf < buffer + size) && (stop < 1) && (connected || login));
	if(stop < 1 && (connected || login) && mail && (line < (User.lines - 6)))
	{
		while(line++ < (User.lines - 5))
		{
			if(mail)	Csi(DEL_RO_LINE);
			Return();
		}
	}

	FreeVec(buffer);
}

struct MenuItem *FindItem(struct Menu *menu, ULONG menuID)
{
	struct Menu			*firstmenu;
	struct MenuItem	*firstitem;
	struct MenuItem	*firstsub;

	for(firstmenu = menu; firstmenu->NextMenu; firstmenu = firstmenu->NextMenu)
	{
		for(firstitem = firstmenu->FirstItem; firstitem->NextItem; firstitem = firstitem->NextItem)
		{
			if(firstitem->SubItem)
			{
				for(firstsub = firstitem->SubItem; firstsub->NextItem; firstsub = firstsub->NextItem)
				{
					if((ULONG)GTMENUITEM_USERDATA(firstsub) == menuID)
						return(firstsub);
				}
			}

			if((ULONG)GTMENUITEM_USERDATA(firstitem) == menuID)
				return(firstitem);
		}
	}
	return(NULL);
}

VOID RefreshStrip()
{
	struct MenuItem *item;

	ClearMenuStrip(Win1);

	if(item = FindItem(menu, MEN_PALETTE))
	{
		if(connected || login)
			item->Flags &= ~ITEMENABLED;
		else
			item->Flags |= ITEMENABLED;
   }
	if(item = FindItem(menu, MEN_LOGIN))
	{
		if(connected || login)
		  item->Flags &= ~ITEMENABLED;
		else
			item->Flags |= ITEMENABLED;
	}
	if(item = FindItem(menu, MEN_SYSOP))
	{
		if(Status.sysop)
			item->Flags |= CHECKED;
		else
			item->Flags &= ~CHECKED;
	}
	if(item = FindItem(menu, MEN_CHAT))
	{
		if(connected || login)
			item->Flags |= ITEMENABLED;
		else
			item->Flags &= ~ITEMENABLED;
	}
	if(item = FindItem(menu, MEN_PLUS))
	{
		if(connected || login)
			item->Flags |= ITEMENABLED;
		else
			item->Flags &= ~ITEMENABLED;
	}
	if(item = FindItem(menu, MEN_MINUS))
	{
		if(connected || login)
			item->Flags |= ITEMENABLED;
		else
			item->Flags &= ~ITEMENABLED;
	}
	if(item = FindItem(menu, MEN_ATA))
	{
		if(connected)
			item->Flags &= ~ITEMENABLED;
		else
			item->Flags |= ITEMENABLED;
	}
	if(item = FindItem(menu, MEN_BUSY))
	{
		if(connected)
			item->Flags &= ~ITEMENABLED;
		else
			item->Flags |= ITEMENABLED;
	}
	if(item = FindItem(menu, MEN_WINDOW))
	{
		if(Status.window)
			item->Flags |= CHECKED;
		else
			item->Flags &= ~CHECKED;
	}
	if(item = FindItem(menu, MEN_KEYBOARD))
	{
		if(keyboard)
			item->Flags |= CHECKED;
		else
			item->Flags &= ~CHECKED;
	}
	if(item = FindItem(menu, MEN_INPUT))
	{
		if(ser_in)
			item->Flags |= CHECKED;
		else
			item->Flags &= ~CHECKED;
	}
	if(item = FindItem(menu, MEN_OUTPUT))
	{
		if(ser_out)
			item->Flags |= CHECKED;
		else
			item->Flags &= ~CHECKED;
	}
	if(item = FindItem(menu, MEN_CAPTURE))
	{
		if(FH_Capture)
			item->Flags |= CHECKED;
		else
			item->Flags &= ~CHECKED;
	}
	if(item = FindItem(menu, MEN_PRINTER))
	{
		if(FH_Printer)
			item->Flags |= CHECKED;
		else
			item->Flags &= ~CHECKED;
	}

	SetMenuStrip(Win1, menu);
}

BOOL LoadLine(STRPTR file, LONG line, STRPTR buff)
{
	LONG size;
	STRPTR ptr, buf, buffer;

	line--;
	buff[0] = 0;

	if(buffer = GetFile(file, &size))
	{
		buf = buffer;
		if(ptr = strchr(buf, '\n'))	*ptr = 0;
		while(line-- && buf < buffer + size && ptr)
		{
			buf = ptr + 1;
			if(ptr = strchr(buf, '\n'))	*ptr = 0;
		}

		if(line == -1 && buf < buffer + size)
		{
			strcpy(buff, buf);
			FreeVec(buffer);
			return(TRUE);
		}
		FreeVec(buffer);
	}

	return(FALSE);
}

VOID ReplaceLine(STRPTR file, LONG line, STRPTR text)
{
	ULONG size;
	BPTR FH;
	STRPTR buffer, buf, ptr;

	if(line < 1)	return;
	line--;

	if(buffer = GetFile(file, &size))
	{
		if(FH = Open(file, MODE_NEWFILE))
		{
			buf = buffer;
			while(line && buf < buffer + size)		/* vorherige zeilen schreiben */
			{
				if(ptr = strchr(buf, '\n'))
				{
					ptr++;
					Write(FH, buf, ptr - buf);
					buf = ptr;
				}
				line--;
			}
			while(line > 0)		/* wenn file zu klein, noetige zeilen einfuegen */
			{
				Write(FH, "\n", 1);
				line--;
			}

			Write(FH, text, strlen(text));		/* text einsetzen */
			Write(FH, "\n", 1);

			if(buf < buffer + size)	/* falls zeile schon existierte nicht nochmal schreiben */
			{
				if(ptr = strchr(buf, '\n'))
				{
					ptr++;
					buf = ptr;
				}
			}

			if(buf < buffer + size && buf)		/* den rest noch dranhaengen */
				Write(FH, buf, buffer + size - buf);

			Close(FH);
		}

		FreeVec(buffer);
	}
	else if(FH = Open(file, MODE_NEWFILE))
	{
		while(line > 0)		/* noetige zeilen einfuegen */
		{
			Write(FH, "\n", 1);
			line--;
		}

		Write(FH, text, strlen(text));		/* text einsetzen */
		Write(FH, "\n", 1);

		Close(FH);
	}
}

LONG FindLine(STRPTR file, STRPTR str)
{
	BOOL more;
	BPTR FH;
	LONG i;
	STRPTR ptr;

	i = 0;

	if(FH = Open(file, MODE_OLDFILE))
	{
		i = 0;
		do
		{
			i++;
			more = FGets(FH, out_buffer, 1000);
			if(ptr = strchr(out_buffer, '\n'))	*ptr = '\0';
		}	while(more && strcmp(out_buffer, str));

		Close(FH);
	}
	else	return(NULL);

	if(more && !strcmp(out_buffer, str))	return(i);
	else	return(NULL);
}

VOID parentdir(STRPTR file)
{
	register long i;

	i = strlen(file) - 1;
	if(file[i] == ':' || i < 0)	return;

	do
		file[i--]='\0';
	while(file[i] != '/' &&	file[i] != ':' &&	i >= 0);
}

WORD __stdargs MyEasyRequest(UBYTE *Text, UBYTE *Gadgets, ...)
{
	struct	EasyStruct	Easy;
	struct	Window *window;
	ULONG		IDCMP = NULL;
	WORD		ret;

	if(!Win1)
	{
		ULONG lock;

		lock = LockIBase(0);
		window = IntuitionBase->ActiveWindow;
		UnlockIBase(lock);
	}
	else	window = Win1;

	BlockWindow(Win1);
	BlockWindow(Win2);

	Easy.es_StructSize	= sizeof(struct EasyStruct);
	Easy.es_Flags			= NULL;
	Easy.es_Title			= "Z-BBS Request";
	Easy.es_TextFormat	= Text;
	Easy.es_GadgetFormat	= Gadgets;

	
	ret = EasyRequestArgs(window, &Easy, &IDCMP, (STRPTR)(&Gadgets + 1));

	ReleaseWindow(Win1);
	ReleaseWindow(Win2);

	return(ret);
}

VOID FindFile(STRPTR path, STRPTR name)
{
	struct FileInfoBlock *entry;
	BPTR lock;
	char f1[256], f2[256];

	if(lock = Lock(path, ACCESS_READ))
	{
		if(entry = (struct FileInfoBlock *)AllocVec(sizeof(struct FileInfoBlock), MEMF_PUBLIC | MEMF_CLEAR))
		{
			if(Examine(lock, (struct FileInfoBlock *)entry) != DOSFALSE)
			{
				ExNext(lock, (struct FileInfoBlock *)entry);
				if(!IoErr())
				{
					if(entry->fib_Size)
					{
						SPrintf(f1, "%ls%ls", path, entry->fib_FileName);
						SPrintf(f2, "%ls%ls", path, name);
						Rename(f1, f2);
					}
				}
			}
			FreeVec(entry);
		}
		UnLock(lock);
	}
}

VOID Clock()
{
	GetDate();

	SetAPen(Win2->RPort, 7);
	SetDrMd(Win2->RPort, JAM2);
	wprintf(Win2->RPort, 497,53, "%ls %ls", date, time);
}

VOID WaitENV()
{
	while(!Exists("ENV:BBS") && CarrierSet())	Delay(50);
	DeleteFile("ENV:BBS");
}

VOID CheckLines(LONG *line)
{
	if(CheckIO(ReadCON))
	{
		WaitIO(ReadCON);
		if(keyboard)	*line = User.lines;
		QueueConsole();
	}

	if(CheckIO(ReadSER))
	{
		WaitIO(ReadSER);
		if(serial_in)	*line = User.lines;
		QueueSerial(); 
	}

	if(*line > User.lines - 2)
	{
		Ask("More [Y/n/c]", NULL, HOTKEY, FALSE);
		if(toupper(wait_buffer[0]) == 'C')
		{
			*line = -1;
		}
		else
		{
			if(toupper(wait_buffer[0]) == 'N')
				wait_buffer[0] = 'Q';
			else
				*line = 0;
		}
	}
}

VOID SystemWartung()
{
	char file[256];

	Location("System Wartung");
	ATCmd(Config.busy);
	SPrintf(file, "Execute %lsPreWartung", Config.scripts);
	StartPrg(file);

	if(Config.log[0])
	{
		char file[256], file2[256];

		SPrintf(file, "%lsLOGFILE", Config.log);
		SPrintf(file2, "%lsLogFile_%ls", Config.log, Status.wartung_date);
		Rename(file, file2);
	}

	Status.calls_today	= 0;
	Status.mails_today	= 0;
	Status.online_today	= 0;
	strcpy(Status.wartung_date, date);
	SPrintf(file, "%lsStatus", Config.system);
	RefreshStatus(file, &Status);

	SPrintf(file, "Execute %lsPostWartung", Config.scripts);
	StartPrg(file);

	HangUp();
	Location("Warte auf RING/CONNECT/FAX");
	ShowSystem();
}

VOID HandleRexx()
{
	STRPTR ptr, ptr2;

/* befehle mit args */
	if(ptr = strchr(rx_msg->rm_Args[0], ' '))
	{
		*ptr = 0;
		if(!strcmp(rx_msg->rm_Args[0], "NETCALL"))
		{
			STRPTR hostname, dialcommand, entpacker, passwort;
			LONG protocol;

			ptr++;

			if(ptr2 = strchr(ptr, ' '))
			{
				*ptr2 = 0;
				hostname = ptr;
				ptr = ptr2 + 1;
			}
			if(ptr2 = strchr(ptr, ' '))
			{
				*ptr2 = 0;
				passwort = ptr;
				ptr = ptr2 + 1;
			}
			if(ptr2 = strchr(ptr, ' '))
			{
				*ptr2 = 0;
				dialcommand = ptr;
				ptr = ptr2 + 1;
			}
			if(ptr2 = strchr(ptr, ' '))
			{
				*ptr2 = 0;
				protocol = atol(ptr);
				ptr = ptr2 + 1;
			}
			entpacker = ptr;

			DoNetCall(hostname, dialcommand, entpacker, passwort, protocol);
			UserLog();
		}
		if(!strcmp(rx_msg->rm_Args[0], "PUFFER"))
		{
			STRPTR netfile, systemname, pointname, entpacker;

			ptr++;

			if(ptr2 = strchr(ptr, ' '))
			{
				*ptr2 = 0;
				netfile = ptr;
				ptr = ptr2 + 1;
			}
			if(ptr2 = strchr(ptr, ' '))
			{
				*ptr2 = 0;
				systemname = ptr;
				ptr = ptr2 + 1;
			}
			if(ptr2 = strchr(ptr, ' '))
			{
				*ptr2 = 0;
				pointname = ptr;
				ptr = ptr2 + 1;
			}
			entpacker = ptr;

/*			SortPuffer(netfile, systemname, pointname, entpacker);
*/		}
	}
/* befehle ohne args */
	else
	{
		if(!strcmp(rx_msg->rm_Args[0], "WARTUNG"))	SystemWartung();
	}

	rx_msg->rm_Result1 = 0;
	rx_msg->rm_Result2 = 0;
	ReplyMsg(rx_msg);
}

VOID wprintf(struct RastPort *rp, UWORD x, UWORD y, UBYTE *string, ...)
{
	UBYTE buff[256];

	VSPrintf(buff, string, (STRPTR)(&string + 1));

	Move(rp, x, y+6);
	Text(rp, buff, strlen(buff));
}

STATIC VOID SetWait(struct Window *win)
{
	STATIC USHORT __chip Stopwatch[(2 + 16) * 2] =
	{
		0x0000,0x0000,

		0x0400,0x07C0,
		0x0000,0x07C0,
		0x0100,0x0380,
		0x0000,0x07E0,
		0x07C0,0x1FF8,
		0x1FF0,0x3FEC,
		0x3FF8,0x7FDE,
		0x3FF8,0x7FBE,
		0x7FFC,0xFF7F,
		0x7EFC,0xFFFF,
		0x7FFC,0xFFFF,
		0x3FF8,0x7FFE,
		0x3FF8,0x7FFE,
		0x1FF0,0x3FFC,
		0x07C0,0x1FF8,
		0x0000,0x07E0,

		0x0000,0x0000
	};

	SetPointer(win, Stopwatch, 16, 16, -6, 0);
}

VOID BlockWindow(struct Window *win)
{
	if(win)
	{
		SetWait(win);
		win->Flags |= RMBTRAP;
	}
}	

VOID ReleaseWindow(struct Window *win)
{
	if(win)
	{
		win->Flags &= ~RMBTRAP;
		ClearPointer(win);
	}
}

VOID ResetLog()
{
	SPrintf(Log.date, "%.5ls", date);
	SPrintf(Log.in, "%.5ls", time);
	SPrintf(Log.baud, "%ld", realbaud);
	Log.out[0]		= Log.user[0]	= 0;
	Log.k_uloads	= Log.k_dloads	= Log.uloads		= Log.dloads		=
	Log.messages	= Log.new_user	= Log.paged_sysop	= Log.pw_hacking	=
	Log.bad_transfers	= 0;
	Log.bad_logoff	= TRUE;
}

struct Protocol *GetProtocol(LONG protocol_number)
{
	struct Protocol *protocol;

	protocol = GetHead(&ProtocolList);
	while(protocol && --protocol_number)	protocol = GetSucc(protocol);

	return(protocol);
}

VOID ShowUser()
{
	SetDrMd(Win2->RPort, JAM1);
	SetAPen(Win2->RPort, 0);
	RectFill(Win2->RPort, 0, 0, Win2->Width, 52);
	SetAPen(Win2->RPort, 3);

	wprintf(Win2->RPort, 3, 2,  "Alias   : %-16.16ls Level: %-8.8ld Ul   : %ld [%ld]", User.alias, User.level, User.uploads, User.bytes_upload / 1024);
	wprintf(Win2->RPort, 507, 2,  "Ansi  : %lc%lc%lc", (User.ansi == 2 ? 'A' : (User.ansi == 1 ? 'a' : '-')), (User.screenblank ? 'B' : '-'), (User.partial_scroll ? 'P' : '-'));
	wprintf(Win2->RPort, 3, 10, "Vorname : %-16.16ls Time : %-8.8ld Dl   : %ld [%ld]", User.first_name, User.time/60, User.downloads, User.bytes_download / 1024);
	wprintf(Win2->RPort, 507, 10, "Lines : %ld", User.lines);
	wprintf(Win2->RPort, 3, 18, "Nachname: %-16.16ls today: %-8.8ld Ratio: %lc%lc%lc [%ls]", User.name, User.time_used/60, (User.b_ratio ? 'B' : '-'), (User.ul_first ? 'F' : '-'), (User.ul_already ? 'A' : '-'), User.ud_ratio);
	wprintf(Win2->RPort, 507, 18, "Editor: %ld", User.editor);
	wprintf(Win2->RPort, 3, 26, "Strasse : %-16.16ls total: %-8.8ld Calls: %-12.12ld Font  : %ls", User.street, (User.time_on+User.time_used)/60, User.calls, (User.amiga ? "Amiga" : "IBM"));
	wprintf(Win2->RPort, 3, 34, "Ort     : %-16.16ls Last : %-8.8ls Vert.: %-12.12ls Msgs  : %ld", User.place, User.time_last, (User.vertreter[0] ? User.vertreter : "keinen"), User.mails_sent);
	wprintf(Win2->RPort, 3, 42, "Telefon : %-16.16ls Gebr.: %-8.8ls Comp.: %.25ls", User.phone, User.birthday, User.terminal);

	SetAPen(Win2->RPort, (depth < 3 ? 3 : 4));
	if(Config.backdrop)
	{
		Move(Win2->RPort, 0, 0);
		Draw(Win2->RPort, Win2->Width, 0);
	}
	Move(Win2->RPort, 0,51);
	Draw(Win2->RPort, Win2->Width, 51);
}

VOID ShowSystem()
{
	SetDrMd(Win2->RPort, JAM1);
	SetAPen(Win2->RPort, 0);
	RectFill(Win2->RPort, 0, 0, Win2->Width, 52);
	SetAPen(Win2->RPort, (depth == 1 ? 1 : 2));

	wprintf(Win2->RPort, 3, 2,  "Anrufe total: %-6ld Mail-Counter: %-6ld Speicher : %ld KB", Status.calls, Status.mail_counter, AvailMem(MEMF_ANY) / 1024);
	wprintf(Win2->RPort, 3, 10, "Anrufe heute: %-6ld Mails heute : %-6ld Sysop    : %ls", Status.calls_today, Status.mails_today, (Status.sysop ? "an" : "aus"));
	wprintf(Win2->RPort, 3, 18, "User total  : %-6ld - 2400      : %-6ld Window   : %ls", Status.users, Status.b_2400, (Status.window ? "an" : "aus"));
	wprintf(Win2->RPort, 3, 26, "User neu    : %-6ld - 9600      : %-6ld", Status.users_new, Status.b_9600);
	wprintf(Win2->RPort, 3, 34, "Auslastung  : %-3ld%%   > 9600      : %-6ld", (100 * Status.online / (Status.time_on + 1)), Status.b_19200);
	wprintf(Win2->RPort, 3, 42, "Online Heute: %-6ld Baudrate    : %-6ld", Status.online_today / 60, Config.baud);

	SetAPen(Win2->RPort, (depth < 3 ? 3 : 4));
	if(Config.backdrop)
	{
		Move(Win2->RPort, 0, 0);
		Draw(Win2->RPort, Win2->Width, 0);
	}
	Move(Win2->RPort, 0, 51);
	Draw(Win2->RPort, Win2->Width, 51);
}
