/**********************************************************************\
 *                               Antrag                               *
 *                                                                    *
 *                         © 1991 G. Glendown                         *
 *                                                                    *
 * `Antrag' ist ein externes Programm für das hervorragende Mailbox-  *
 *Programm Euromail. Hiermit ist -für Ansi und VT100-User- eine etwas *
 *         komfortablere Eintragung in der Userliste möglich.         *
 *                                                                    *
 *  Außerdem soll `Antrag' noch als Beispiel für die Verwendung der   *
 *serlib.library dienen. Neben der eigentlichen Verwendung der Library*
 * Funktionen sind noch einige Funktionen implementiert, die für die  *
 *   Programmierung von Online-Games sehr interessant sein können.    *
 *                                                                    *
 *`Antrag' ist Freeware. Der kommerzielle Vertrieb (und dazu zähle ich*
 *nahezu alle deutschen `PD-Händler') ist nur mit meiner schriftlichen*
 *                        Genehmigung erlaubt.                        *
\**********************************************************************/

/**********************************************************************\
 *to programmers: if you use part of this program in your program(s), *
 *      I would appreciate a copy of the source & executeable...      *
\**********************************************************************/

#define scrdef	NewScreenStructure
#define windef	NewWindowStructure1
#define WINFB	0x01

struct NewScreen NewScreenStructure = {
	0,0,640,211,2,0,1,HIRES,CUSTOMSCREEN,NULL,NULL,NULL,NULL};

#define NEWSCREENSTRUCTURE NewScreenStructure

USHORT Palette[] = {
	0x0000,0x0FFF,0x0888,0x035B};

#define PALETTE Palette

USHORT chip ImageData1[] = {
	0x0000,0x0000,0x7FFF,0xFE00,0x7FFF,0xFE00,0x7803,0xFE00,
	0x78FF,0xFE00,0x7880,0x3E00,0x7F80,0x3E00,0x7F80,0x3E00,
	0x7FFF,0xFE00,0x7FFF,0xFE00,0xFFFF,0xFE00,0xFFFF,0xFE00,
	0xFFFF,0xFC00,0xF001,0xFC00,0xF001,0xFC00,0xF000,0x1C00,
	0xF07F,0xDC00,0xF07F,0xDC00,0xFF7F,0xDC00,0xFF00,0x1C00,
	0xFFFF,0xFC00,0x0000,0x0000};

struct Image Image1 = {
	0,0,23,11,2,ImageData1,0x0003,0x0000,NULL};

USHORT chip ImageData2[] = {
	0xFFFF,0xFE00,0xFFFF,0xFC00,0xFFFF,0xFC00,0xF803,0xFC00,
	0xF8FF,0xFC00,0xF882,0x3C00,0xFFFE,0x3C00,0xFF80,0x3C00,
	0xFFFF,0xFC00,0xFFFF,0xFC00,0x0000,0x0000,0x0000,0x0000,
	0x7FFF,0xFE00,0x7001,0xFE00,0x7001,0xFE00,0x7000,0x1E00,
	0x707D,0xDE00,0x7001,0xDE00,0x7F7F,0xDE00,0x7F00,0x1E00,
	0x7FFF,0xFE00,0xFFFF,0xFE00};

struct Image Image2 = {
	0,0,23,11,2,ImageData2,0x0003,0x0000,NULL};

struct Gadget Gadget1 = {
	NULL,617,0,23,11,GADGHIMAGE+GADGIMAGE,RELVERIFY,BOOLGADGET,
	(APTR)&Image1,(APTR)&Image2,NULL,NULL,NULL,WINFB,NULL};

struct NewWindow NewWindowStructure1 = {
	0,0,640,211,0,1,GADGETUP+CLOSEWINDOW+VANILLAKEY,
	BORDERLESS+ACTIVATE+RMBTRAP+NOCAREREFRESH,
	&Gadget1,NULL,NULL,NULL,NULL,5,5,-1,-1,CUSTOMSCREEN};

#include <serlib.h>
#include <em-strukturen.h>
#include "antrag.proto"

/* return-values of the `GetString'-function */
#define EMPTY	0x01	/* an empty input line */
#define OK		0x02	/* everything OK... */
#define CTRLX	0x03	/* aborted with CTRL-X or CTRL-C */
#define NOCD	0x04	/* carrier lost */
#define NACK	0x05	/* not OK... (not used by GetString) */

/* Some definitions for GetString ... */
#define HIDE		(1<<0)			/* Only Echo `*' */
#define ALLOWTABLE	(1<<1)			/* The table contains allowed chars */
#define FORBIDTABLE	(1<<2)			/* The table contains forbidden chars */
#define ALPHA		(1<<3)			/* Allow Alpha-Chars (A-z) */
#define GERMAN		(1<<4)			/* Allow german chars (äöüÄÖÜß) */
#define NUM			(1<<5)			/* Allow numbers */
#define OTHER		(1<<6)			/* Other ASCII-Chars */
#define SPACES		(1<<7)			/* Allow Spaces */
#define ALLOWEMPTY	(1<<8)			/* Allow empty string */
#define KEYS		(ALPHA|NUM|OTHER)

/* Some character definitions */
#define NORMAL	0x01
#define BACKSP	0x02
#define RETURNCHAR	0x03
#define BREAKCHAR	0x04
#define IGNORE	0x05
#define SPACE	0x06

static char CLS[]={12,27,"[2J"};
static char BEEP[]={7,0};
static char DLL[]={27,"[2K"};
static char ESC[]={27,'[',0};
static char space[]={"                                                                                "};
static char SP[]={" "};
struct SerLibBase *SerLibBase;
struct SerStatus ss;
struct SerLibData	*sld;
char buf[128],temp[128],tmp[128];
struct timerequest *tr=NULL;
struct MsgPort	*tport;
struct Message	*tmsg;
struct timeval	tv;

char cl[2][128];
int cx[2],cy[2],bw[2],lc[2],cpos[2],con=1,CORRECT;
ULONG baud;

struct	Prefer ep,*ep2;

BOOL Ansi,LASTCR;
char BBSBaud[32],BBSUser[80],BBSStatus[32],BBSOnline[32],BBSRest[32],
     BBSDev[32],BBSTerm[32];

struct IntuitionBase *IntuitionBase;
struct IntuiMessage *msg;
LONG class;
int code,line;

/*#define CheckCD(a)	(1==1)*/

struct GfxBase *GfxBase;

struct ViewPort *vp;
struct RastPort *rp;
struct Screen *scr=NULL;
struct Window *win=NULL;

int ser;

char MyTable[]={	"\tRazAZ!?__", 0 };

struct Usereintrag *user=NULL;
struct NewUser {
	UBYTE Uname[16];
	UBYTE Passw[9];
	UBYTE Name[20];
	UBYTE Vorname[20];
	UBYTE Strasse[25];
	UBYTE PlzOrt[25];
	UBYTE Telefon[25];
	UBYTE Rechner[9];
	UBYTE Terminal[9];
	UBYTE Sprache[9];
} newuser;

long usersize;
int numuser;

char protokoll[128],newusf[128];

char comp[][9]={"-","A1000","A500","A2000","A2500","A3000","Atari ST",
				"Atari TT","PC/XT/AT","Unix"};
char term[][9]={"TTY","ANSI","VT-100"};

char	SERDEVNAME[]={"serial.device\0<------------------>"};
int		SERUNIT;
ULONG	BBS_FLAGS;

void main(long argc,char *argv[])
{
ULONG rw;
int t;
FILE *f;
	SERUNIT=0;
	BBS_FLAGS=0L;
	ScanData();
	OpenStuff();
	CORRECT=0;
	if (con==0) {
		if (argc) {
			if (argv[1][0]=='B')
				baud=atol(&(argv[1][1]));
		}
		if (!(sld=OpenSerial(SERDEVNAME,SERUNIT,baud,8,1,(ULONG)(BBS_FLAGS|SERF_SHARED))))
			printf("Keine Verbindung zum Modem möglich!\n"),ex();
		ChangeData(sld,baud,8,1,(ULONG)(BBS_FLAGS|SERF_SHARED));
	}
	SendString(CLS);
	PositionText(32,0,"User-Antrag");
	PositionText(32,1,"-----------");
	PositionText(0,3,"Die Anmelde-Prozedur kann jederzeit durch Eingabe von CTRL-X abgebrochen");
	PositionText(0,4,"werden...");


enteruname:
	line=6;
	PositionText(0,line,"1. Gewuenschter Username:                                 ");
nameloop:
	rw=GetString(temp,15,ALLOWTABLE,MyTable,win,27,line);
	switch (rw) {
		case OK:
			break;
		case CTRLX:
			if (AskAbort(win,"Antrag abbrechen ?")!=NACK)
				ex();
			else goto nameloop;
			break;
		case NOCD:
			ex();
	}
	for (t=0;t<numuser;t++) {
		if (!stricmp(user[t].Uname,temp)) {
			PositionText(27,line,"Username bereits vorhanden!");
			Delay(50L);
			PositionText(27,line,"                           ");
			goto nameloop;
		}
	}

	strncpy(newuser.Uname,temp,16);
	if (CORRECT)	goto correct;
	line=7;

pwloop1:
	PositionText(0,line,"2. Bitte Passwort waehlen:                            ");
	rw=GetString(temp,8,KEYS|HIDE|ALLOWEMPTY,NULL,win,27,line);
	switch (rw) {
		case OK:
			break;
		case CTRLX:
			if (AskAbort(win,"Antrag beenden ?")!=NACK)
				ex();
			else goto pwloop1;
			break;
		case NOCD:
			ex();
	}
	if (strlen(temp)<3) {
		PositionText(10,24,"Passwort zu kurz! Eingabe wiederholen!");
		Delay(50L);
		PositionText(10,24,"                                      ");
		goto pwloop1;
	}
pwloop2:
	PositionText(0,line+1,"   Passwort wiederholen:                             ");
	rw=GetString(tmp,8,KEYS|HIDE,NULL,win,27,line+1);
	switch (rw) {
		case OK:
			break;
		case CTRLX:
			if (AskAbort(win,"Antrag beenden ?")!=NACK)
				ex();
			else goto pwloop2;
			break;
		case NOCD:
			ex();
	}
	if (stricmp(tmp,temp)) {
		PositionText(10,24,"Passworte stimmen nicht! Eingabe wiederholen!");
		Delay(50L);
		PositionText(10,24,"                                             ");
		PositionText(0,line+1,"                                             ");
		goto pwloop1;
	}
	strncpy(newuser.Passw,tmp,9);

	if (CORRECT) {
		PositionText(0,line,"                                             ");
		PositionText(0,line+1,"                                            ");
		goto correct;
	}
	else
		PositionText(0,line,"2. Passwort                                  ");

entervname:
	line=8;
	PositionText(0,line,"3. Vorname :                                             ");
vnameloop:
	rw=GetString(temp,19,KEYS|SPACES|GERMAN|ALLOWEMPTY,NULL,win,15,line);
	switch (rw) {
		case OK:
		case EMPTY:
			break;
		case CTRLX:
			if (AskAbort(win,"Antrag abbrechen ?")!=NACK)
				ex();
			else goto vnameloop;
			break;
		case NOCD:
			ex();
	}
	strcpy(newuser.Vorname,temp);
	if (CORRECT)	goto checkname;

entername:
	line=9;
	PositionText(0,line,"4. Nachname:                                             ");
nnameloop:
	rw=GetString(temp,19,KEYS|SPACES|GERMAN,NULL,win,15,line);
	switch (rw) {
		case OK:
			break;
		case CTRLX:
			if (AskAbort(win,"Antrag abbrechen ?")!=NACK)
				ex();
			else goto nnameloop;
			break;
		case NOCD:
			ex();
	}
	strcpy(newuser.Name,temp);
checkname:
	for (t=0;t<numuser;t++) {
		if (!stricmp(user[t].Name,newuser.Name)) {
			if (!stricmp(user[t].Vorname,newuser.Vorname)) {
				sprintf(temp,"`%s %s' hat schon einen Account.",user[t].Vorname,user[t].Name);
				PositionText(10,22,temp);
				t=AskAbort(win,"Antrag beenden ?");
				PositionText(10,22,"                                                                  ");
				if (t!=NACK) ex();
				else t=numuser;
			}
		}
	}
	if (CORRECT)	goto correct;

enterstreet:
	line=10;
	PositionText(0,line,"5. Strasse :                                              ");
streetloop:
	rw=GetString(temp,24,KEYS|SPACES|GERMAN|ALLOWEMPTY,NULL,win,15,line);
	switch (rw) {
		case OK:
			break;
		case CTRLX:
			if (AskAbort(win,"Antrag abbrechen ?")!=NACK)
				ex();
			else goto streetloop;
			break;
		case NOCD:
			ex();
	}
	strcpy(newuser.Strasse,temp);
	if (CORRECT) goto correct;

entertown:
	line=11;
	PositionText(0,line,"6. PLZ ORT :                                            ");
placeloop:
	rw=GetString(temp,24,KEYS|SPACES|GERMAN,NULL,win,15,line);
	switch (rw) {
		case OK:
			break;
		case CTRLX:
			if (AskAbort(win,"Antrag abbrechen ?")!=NACK)
				ex();
			else goto placeloop;
			break;
		case NOCD:
			ex();
	}
	strcpy(newuser.PlzOrt,temp);
	if (CORRECT)	goto correct;

entertel:
	line=12;
	PositionText(0,line,"7. Telefon :                                             ");
telloop:
	rw=GetString(temp,24,ALLOWTABLE,"01234567890()/-+ ",win,15,line);
	switch (rw) {
		case OK:
			break;
		case CTRLX:
			if (AskAbort(win,"Antrag abbrechen ?")!=NACK)
				ex();
			else goto telloop;
			break;
		case NOCD:
			ex();
	}
	strcpy(newuser.Telefon,temp);
	if (CORRECT)	goto correct;
	line=13;

entercomp:
	PositionText(0,line,"-1- Amiga 1000   -2- Amiga 500    -3- Amiga 2000");
	PositionText(0,line+1,"-4- Amiga 2500   -5- Amiga 3000   -6- Atari ST");
	PositionText(0,line+2,"-7- Atari TT     -8- PC/XT/AT     -9- Unix-Rechner");
	PositionText(0,line+3,"-0- andere");
comploop:
	PositionText(0,line+4,"Bitte waehlen:     ");
	rw=GetString(temp,1,NUM,NULL,win,16,line+4);
	switch (rw) {
		case OK:
			if (atoi(temp)>9)
				goto comploop;
			break;
		case CTRLX:
			if (AskAbort(win,"Antrag abbrechen ?")!=NACK)
				ex();
			else goto comploop;
			break;
		case NOCD:
			ex();
	}
	strcpy(newuser.Rechner,comp[atoi(temp)]);
	for (t=0;t<5;t++)
		PositionText(0,line+t,"                                                               ");
	PositionText(0,line,"8. Computer: ");
	PositionText(15,line,newuser.Rechner);
	if (CORRECT)	goto correct;
	line=14;

enterterm:
	PositionText(0,line,"-0- TTY     -1- ANSI     -2- VT-100");
termloop:
	PositionText(0,line+1,"Bitte Terminal-Emulation waehlen:     ");
	rw=GetString(temp,1,ALLOWTABLE,"012",win,35,line+1);
	switch (rw) {
		case OK:
			break;
		case CTRLX:
			if (AskAbort(win,"Antrag abbrechen ?")!=NACK)
				ex();
			else goto termloop;
			break;
		case NOCD:
			ex();
	}
	strcpy(newuser.Terminal,term[atoi(temp)]);
	PositionText(0,line,"9. Terminal:                                       ");
	PositionText(0,line+1,"                                            ");
	PositionText(15,line,newuser.Terminal);
	if (CORRECT)	goto correct;

finalquestion:
	PositionText(0,16,"Eingaben Korrekt (J/n/q) ?");
	rw=GetString(temp,1,ALLOWTABLE|ALLOWEMPTY,"JNQjnq",win,28,16);
	switch (rw) {
		case OK:
			*temp=toupper(*temp);
			switch (*temp) {
				case 'J':
					goto finished;
					break;
				case 'Q':
					if (AskAbort(win,"Antrag abbrechen ?")!=NACK)
						ex();
					else goto finalquestion;
					break;
				case 'N':
					goto correct;
					break;
			}
			break;
		case CTRLX:
			if (AskAbort(win,"Antrag abbrechen ?")!=NACK)
				ex();
			else goto finalquestion;
			break;
		case EMPTY:
			goto finished;
			break;
		case NOCD:
			ex();
	}

finished:
	if (f=fopen(newusf,"w")) {
		fprintf(f,"User:  %s\nPW:    %s\n",newuser.Uname,newuser.Passw);
		fprintf(f,"Name:  %s %s\n",newuser.Vorname,newuser.Name);
		fprintf(f,"Str.:  %s\nOrt:   %s\n",newuser.Strasse,newuser.PlzOrt);
		fprintf(f,"Tel.:  %s\nComp:  %s\n",newuser.Telefon,newuser.Rechner);
		fprintf(f,"Terminal: %s\nSprache: %s\n",newuser.Terminal,newuser.Sprache);
		fprintf(f,"Baudrate des Anrufs: %s\n",BBSBaud);
		fclose(f);
	}
	else {
		ToProto("Konnte Ausgabefile nicht öffnen!");
		printf("Achtung! Systemfehler! Bitte den Sysop benachrichtigen!\n");
	}
	newusf[0]='\0';
	PositionText(0,23,"Antrag abgesandt...");
	Delay(100L);
	ex();

correct:
	if (CORRECT) {
		PositionText(15,13,"          ");
		PositionText(15,14,"          ");
		PositionText(15,14,newuser.Terminal);
		PositionText(15,13,newuser.Rechner);
	}
	PositionText(0,16,"Welche Zeile ändern ? (0=Fertig)");
correct2:
	rw=GetString(temp,1,ALLOWTABLE,"\tR09",win,34,16);
	switch (rw) {
		case OK:
			break;
		case CTRLX:
			if (AskAbort(win,"Antrag abbrechen ?")!=NACK)
				ex();
			else goto correct2;
			break;
		case NOCD:
			ex();
	}
	PositionText(0,16,"                                    ");
	CORRECT=1;
	switch (atoi(temp)) {
		case 0:
			CORRECT=0;
			goto finalquestion;
			break;
		case 1:
			goto enteruname;
			break;
		case 2:
			line=17;
			goto pwloop1;
			break;
		case 3:
			goto entervname;
			break;
		case 4:
			goto entername;
			break;
		case 5:
			goto enterstreet;
			break;
		case 6:
			goto entertown;
			break;
		case 7:
			goto entertel;
			break;
		case 8:
			line=16;
			goto entercomp;
			break;
		case 9:
			line=16;
			goto enterterm;
			break;
	}
}

/**********************************************************************\
 *                              AskAbort                              *
 *                                                                    *
 *      Ask the user if he really wants to abort what he did...       *
\**********************************************************************/

ULONG AskAbort(struct Window *win,char *txt)
{
ULONG mask,rw,len,result;
int l;
	mask=((1L<<(win->UserPort->mp_SigBit))|(1L<<(tport->mp_SigBit)));
	PositionText(10,23,txt);
	l=11+strlen(txt);
	rw=NOCD;
loop1:
	DoTime(tr,20);
	buf[0]='\0';
	buf[1]='\0';
	if (!con) {
		RecvSer(sld,buf,1);
		result=WaitSer(sld,mask);
	}
	else
		result=Wait(mask);
	Disable();
	if (!CheckIO((struct IORequest *)tr)) {
		AbortIO((struct IORequest *)tr);
		WaitIO((struct IORequest *)tr);
	}
	if (!con) {
		if (!CheckIOSer(sld)) {
			AbortIOSer(sld,ABORT_RECV);
			WaitSer(sld,0L);
		}
	}
	Enable();
	if (!con) {
		if (!(CheckCD(sld))) return(NOCD);
		len=strlen(buf);
		if (len) goto gotachar;
		if (SerBuffer(sld)>0) {
			len=ReadSer(sld,buf,1);
			if (len) {
gotachar:
				rw=NOCD;
				switch (*buf) {
					case 'J':
					case 'j':
						rw=OK;
						break;
					case 'N':
					case 'n':
						rw=NACK;
						break;
					case 3:
					case 24:
						rw=CTRLX;
						break;
					case 13: 
					case 10:
						rw=EMPTY;
						break;
					default:
						Flash(scr);
				}
				EmptyBuf();
			}
		}
	}
	if (msg=(struct IntuiMessage *)GetMsg(win->UserPort)) {
		if (msg->Class==VANILLAKEY) {
			switch (msg->Code) {
				case 'J':
				case 'j':
					rw=OK;
					break;
				case 'N':
				case 'n':
					rw=NACK;
					break;
				case 3:
				case 24:
					rw=CTRLX;
					break;
				case 13: 
				case 10:
					rw=EMPTY;
					break;
				default:
					Flash(scr);
			}
		}
		while (msg) {
			ReplyMsg((struct Message *)msg);
			msg=(struct IntuiMessage *)GetMsg(win->UserPort);
		}
	}
	if (rw!=NOCD) {
		PositionText(10,23,"                                     ");
		return(rw);
	}
	else goto loop1;
}

/**********************************************************************\
 *                             GetString                              *
\**********************************************************************/
/*
Now, this one's a real jewel. You have LOTS of possibilities with this
function. Let's do the params one by one...

txt - pointer to the text buffer, which is
mlen  bytes long. Any inputs that would lead to a longer string are
      ignored.
flags With this ULONG, you define how GetString will behave. Currently, the
      following flag types are understood:
        HIDE		- characters typed are echoed as `*' (useful for PW,
                      etc.)
        ALLOWTABLE	- the table-pointer points to a set of characters that
                      are allowed
        FORBIDTABLE	- the table-pointer points to a set of characters that
                      are forbidden
        ALPHA		- allow all alpha-chars (a-z, A-Z)
        GERMAN		- allow german chars (äöüÄÖÜß)
        NUM			- allow numbers
        OTHER		- allow other ASCII-chars
        SPACES		- allow Space and TAB (Tab is converted to a Space)
        ALLOWEMPTY	- permit an empty input
        KEYS		- Kombination of ALPHA, NUM and OTHER
      Just about the only thing that is missing right now is an automatic
      conversion of PC or Atari special characters (äöü...)
table a table of characters that are either allowed or forbidden
      additionally to the chars already defined by the flag-bits.
      This one is pretty smart two. You can have two different types of
      tables: either one that explicitely contains every characters, or a
      range of characters (the latter being specified by the table starting
      with the two chars `\t' and `R'.
      So, instead of writing:
      "1234567890"
      to include all numbers, you could also write:
      "\tR09"
      As you cannot mix the two table kinds, to define just a single
      character in the range-table, just duplicate the char:
      "\tR09--//"
      This table will allow all numbers, plus the chars `-' and '/'.
      As noted before, a table can either be an `Allowtable' or a
      `Forbidtable'. No matter what kind it is, it will be looked at first.
      So, if you haven't set the Flag `SPACES' in the Flags-field, and have
      an allow table that includes a Space, it will be returned as a valid
      char. On the other hand, by specifying a forbid table, you could,
      e.g., forbid the use of the chars `g' and `h' by specifying a
      apropriate table and setting the FORBIDTABLE flag, plus the other
      flags you might need. Now, the user can not enter a `g' or `h' anymore.
win - a pointer to a Window-structure, in which the output is to be
      performed.
posx, position of the input `window'. Make sure that posx+mlen doesn't
posy  exceed the size of the window (remember there is a cursor displayed,
      so the maximum size useable for a 640-screen would be 78)
*/

ULONG GetString(txt,mlen,flags,table,win,posx,posy)
char *txt;
int mlen;
ULONG flags;
char *table;
struct Window *win;
int posx,posy;
{
ULONG mask,result,_len,t,len=0;
int type;
	LASTCR=FALSE;
	mask=((1L<<(win->UserPort->mp_SigBit))|(1L<<(tport->mp_SigBit)));
	PositionChar(posx,posy,'_');
loop:
	buf[0]='\0';
	buf[1]='\0';
	DoTime(tr,50L);	/* 1 Sekunde timeout */
	if (!con) {
		RecvSer(sld,buf,1);
		result=WaitSer(sld,mask);
	}
	else
		result=Wait(mask);
	Disable();
	if (!CheckIO((struct IORequest *)tr)) {
		AbortIO((struct IORequest *)tr);
		WaitIO((struct IORequest *)tr);
	}
	if (!con) {
		if (!CheckIOSer(sld)) {
			AbortIOSer(sld,ABORT_RECV);
			WaitSer(sld,0L);
		}
	}
	Enable();
	if (!con) {
		if (!CheckCD(sld)) return(NOCD);
		if (_len=strlen(buf))
			goto gotitagain;
		if (SerBuffer(sld)>0) {
			_len=ReadSer(sld,buf,64);
gotitagain:
			for (t=0;t<_len;t++) {
				if (type=CheckChar(buf[t],flags,table)) {
					switch (type) {
						case NORMAL:
							if (len<mlen) {
								if (flags&HIDE)
									PositionChar(posx+len,posy,'*');
								else
									PositionChar(posx+len,posy,buf[t]);
								txt[len]=buf[t];
								len++;
								PositionChar(posx+len,posy,'_');
							}
							else
								Flash(scr);
							break;
						case SPACE:
							if (len<mlen) {
								if (flags&HIDE)
									PositionChar(posx+len,posy,'*');
								else
									PositionChar(posx+len,posy,' ');
								txt[len]=' ';
								len++;
								PositionChar(posx+len,posy,'_');
							}
							else
								Flash(scr);
							break;
						case BACKSP:
							if (len) {
								PositionText(posx+len-1,posy,"_ ");
								len--;
								txt[len]='\0';
							}
							else
								Flash(scr);
							break;
						case RETURNCHAR:
							EmptyBuf();
							PositionChar(posx+len,posy,' ');
							txt[len]='\0';
							if (len>0) {
								return(OK);
							}
							else {
								if (flags&ALLOWEMPTY)
									return(EMPTY);
								else {
									PositionChar(posx+len,posy,'_');
									Flash(scr);
								}
							}
							break;
						case BREAKCHAR:
							EmptyBuf();
							PositionChar(posx+len,posy,' ');
							txt[0]='\0';
							return(CTRLX);
						case IGNORE:
							Flash(scr);
							break;
					}
				}
			}
		}
	}
	msg=(struct IntuiMessage *)GetMsg(win->UserPort);
	while (msg) {
		class=msg->Class;
		code=msg->Code;
		switch (class) {
			case VANILLAKEY:
				if (type=CheckChar(code,flags,table)) {
					switch (type) {
						case NORMAL:
							if (len<mlen) {
								if (flags&HIDE)
									PositionChar(posx+len,posy,'*');
								else
									PositionChar(posx+len,posy,code);
								txt[len]=code;
								len++;
								PositionChar(posx+len,posy,'_');
							}
							else
								Flash(scr);
							break;
						case SPACE:
							if (len<mlen) {
								if (flags&HIDE)
									PositionChar(posx+len,posy,'*');
								else
									PositionChar(posx+len,posy,' ');
								txt[len]=' ';
								len++;
								PositionChar(posx+len,posy,'_');
							}
							else
								Flash(scr);
							break;
						case BACKSP:
							if (len)
								PositionText(posx+len-1,posy,"_ "),
								len--,
								txt[len]='\0';
							else
								Flash(scr);
							break;
						case RETURNCHAR:
							EmptyBuf();
							txt[len]='\0';
							PositionChar(posx+len,posy,' ');
							if (len)
								return(OK);
							else
								if (flags&ALLOWEMPTY)
									return(EMPTY);
								else
									PositionChar(posx+len,posy,'_'),
									Flash(scr);
							break;
						case BREAKCHAR:
							EmptyBuf();
							txt[0]='\0';
							PositionChar(posx+len,posy,' ');
							return(CTRLX);
						case IGNORE:
							Flash(scr);
							break;
					}
				}
				break;
		}
		ReplyMsg((struct Message *)msg);
		msg=(struct IntuiMessage *)GetMsg(win->UserPort);
	}
	goto loop;
}

void Flash(struct Screen *scr)
{
	DisplayBeep(scr);
	SendString(BEEP);
}

char AlphaTable[]={	"\tRazAZ", 0 };
char NumTable[]={ 	"\tR09", 0};
char GermanTable[]={"äöüÄÖÜß",0};
char OtherTable[]={	"\tR!/:?[`{~",0};

/**********************************************************************\
 *                             CheckChar                              *
 *                                                                    *
 *              Checks whether a char is allowed or not               *
\**********************************************************************/

ULONG CheckChar(char c,ULONG flags,char *table)
{
BOOL ALLOWED=FALSE;

	if (flags&ALLOWTABLE) {
		if (!(InTable(c,table)))
			ALLOWED=FALSE;
		else ALLOWED=TRUE;
	}
	if (flags&FORBIDTABLE) {
		if (InTable(c,table))
			ALLOWED=FALSE;
		else ALLOWED=TRUE;
	}
	if (c==10) {
		if (LASTCR) {
			LASTCR=FALSE;
			return(IGNORE);
		}
		else return(RETURNCHAR);
	}
	if (c==13) {
		LASTCR=TRUE;
		return(RETURNCHAR);
	}
	if (c==8) return(BACKSP);
	if ((c==24)||(c==3))	return(BREAKCHAR);
	if (flags&(ALLOWTABLE|FORBIDTABLE)) {
		if (ALLOWED)
			return(NORMAL);
		else
			return(IGNORE);
	}
	if (flags&ALPHA)
		if (InTable(c,AlphaTable))
			return(NORMAL);
	if (flags&GERMAN)
		if (InTable(c,GermanTable))
			return(NORMAL);
	if (flags&NUM)
		if (InTable(c,NumTable))
			return(NORMAL);
	if (flags&OTHER)
		if (InTable(c,OtherTable))
			return(NORMAL);
	if (flags&SPACES)
		if ((c=='\t')||(c==' '))
			return(SPACE);
	return(IGNORE);
}

/**********************************************************************\
 *                              InTable                               *
 *                                                                    *
 *        Check whether a char is found in the table supplied         *
\**********************************************************************/

BOOL InTable(char c,char *tb)
{
	if ((*tb=='\t')&&(tb[1]=='R')) {	/* Hey, somebody's using a RangeTable! */
		tb+=2;
		while (*tb) {
			if ((c>=*tb)&&(c<=tb[1]))
				return(TRUE);
			tb+=2;
		}
	}
	else {
		while (*tb) {
			if (*tb==c) return(TRUE);
			tb++;
		}
	}
}

/**********************************************************************\
 *                              EmptyBuf                              *
 *                                                                    *
 *                     Clean up the serial buffer                     *
\**********************************************************************/

void EmptyBuf()
{
ULONG len;
char buf[128];
	if (sld) {
		len=SerBuffer(sld);
		while (len) {
			ReadSer(sld,buf,126);
			len=SerBuffer(sld);
		}
	}
}

VOID SendString(char *txt)
{
	if (!con)
		WriteSer(sld,txt,strlen(txt));
}

/**********************************************************************\
 *                              ScanData                              *
 *                                                                    *
 *                 Find out some stuff about the user                 *
\**********************************************************************/

VOID ScanData()
{
FILE	*f;
BPTR 	fh;
char str[256];
long pos;
BOOL _OK;
	if (f=fopen("ram:userParam","r")) {
		getstring(BBSBaud,31,f);
		getstring(BBSUser,79,f);
		getstring(BBSStatus,31,f);
		getstring(BBSOnline,31,f);
		getstring(BBSRest,31,f);
		getstring(BBSDev,31,f);
		getstring(BBSTerm,31,f);
		fclose(f);
		baud=atol(BBSBaud);
		con=atoi(BBSDev);
		strupr(BBSTerm);
		if (strnicmp(BBSTerm,"TTY",3))
			Ansi=TRUE;
		else
			Ansi=FALSE;
		if (baud<300) return;
	}
	else
		strcpy(BBSBaud,"Unknown");
	_OK=FALSE;
	if (fh=Open("ram:em-param",MODE_OLDFILE)) {
		if (Read(fh,str,128L)>4) {
			ep2=(struct Prefer *)atol(str);
			_OK=TRUE;
		}
		if (fh) Close(fh);
	}
	if (!_OK) {
		if (fh=Open("s:euro.defslc",MODE_OLDFILE)) {
			if (Read(fh,&ep,sizeof(struct Prefer))) {
				ep2=&ep;
				_OK=TRUE;
			}
			Close(fh);
		}
	}
	if (_OK) {
		SERUNIT=ep2->serdat.Unit;
		strcpy(SERDEVNAME,ep2->serdat.SerName);
		strcat(SERDEVNAME,".device");
		strcpy(str,ep2->userpath);
		strcat(str,"userdatei");
		strcpy(protokoll,ep2->protokollpath);
		strcpy(newusf,ep2->persoenlichpath);
		BBS_FLAGS=SERF_RAD_BOOGIE;
		if (!(ep2->serdat.Xon&1))
			BBS_FLAGS|=SERF_XDISABLED;
		if (ep2->serdat.Xon&2)
			BBS_FLAGS|=SERF_7WIRE;
		strcat(newusf,BBSUser);
		strcat(newusf,"/Antrag");
		if (fh=Open(str,MODE_OLDFILE)) {
			Seek(fh,0L,OFFSET_END);
			usersize=pos=Seek(fh,0L,OFFSET_BEGINNING);
			if (user=(struct Usereintrag *)AllocMem(pos,MEMF_CLEAR)) {
				Read(fh,user,pos);
				numuser=pos/sizeof(struct Usereintrag);
			}
			else {
				numuser=0;
				ToProto("\nNicht genug Speicher für Userstruktur! ");
			}
			Close(fh);
		}
		else
			ToProto("\nUserdatei nicht zu öffnen! ");
	}
}

VOID OpenStuff()
{
BPTR op;
	if (!(IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",0L)))
		ex();
	if (!(GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",0L)))
		ex();
	if (!(SerLibBase=(struct SerLibBase *)OpenLibrary("serlib.library",2L))) {
		printf("Konnte SerLib.Library nicht öffnen!\n");
		ex();
	}
	if (!(tr=OpenTimer())) ex();
	if (!(scr=OpenScreen(&scrdef))) {
		puts("Konnte Screen nicht öffnen!\n");
		ex();
	}
	windef.Screen=scr;
	if (!(win=OpenWindow(&windef))) {
		puts("Konnte Fenster nicht öffnen!\n");
		ex();
	}
	vp=&(scr->ViewPort);
	rp=&(scr->RastPort);
	LoadRGB4(vp,Palette,4L);
	SetDrMd(rp,JAM2);
	SetAPen(rp,1L);
}

VOID ex()
{
FILE *f;
	if (user) FreeMem(user,usersize);
	if (tr) CloseTimer(tr);
	if (win) CloseWindow(win);
	if (scr) CloseScreen(scr);
	if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
	if (GfxBase) CloseLibrary((struct Library *)GfxBase);
	if (sld) CloseSerial(sld);
	if (SerLibBase) CloseLibrary((struct Library *)SerLibBase);

	if (strlen(newusf)) {
		if (f=fopen(newusf,"w")) {
			fprintf(f,"Abgebrochen");
			fclose(f);
		}
	}
	exit(0);
}

VOID getstring(a,l,f)
char *a;
int l;
FILE *f;
{
	fgets(a,l,f);	/* das 'a,l,f' ist Zufall, wirklich! */ 
	a[strlen(a)-1]='\0';
}

VOID PositionText(x,y,txt)
int x,y;
char *txt;
{
char temp[128];
	if (!con) {
		SendString(ESC);
		sprintf(temp,"%d;%dH%s",y+1,x+1,txt);
		SendString(temp);
	}
	DisplayString(x,y,txt);
}

void PositionChar(int x,int y, char c)
{
char temp[16];
	if (!con) {
		SendString(ESC);
		sprintf(temp,"%d;%dH%c",y+1,x+1,c);
		SendString(temp);
	}
	DisplayChar(x,y,c);
}

struct timerequest *OpenTimer()
{
struct timerequest *tr;
	if (!(tport=CreatePort(0,0))) {
		printf("Konnte einen Port nicht erzeugen...\n");
		return(0L);
	}
	if (!(tr=(struct timerequest *)CreateExtIO(tport,(long)sizeof(struct timerequest)))) {
		printf("Probs bei CreateExtIO\n");
		return(0L);
	}
	if (OpenDevice(TIMERNAME,(ULONG)UNIT_VBLANK,(struct IORequest *)tr,0L)) {
		printf("Opendevice für Timer fehlgeschlagen...\n");
		DeleteExtIO((struct IORequest *)tr);
		tr=NULL;
		return(0L);
	}
	return(tr);
}

void CloseTimer(struct timerequest *tr)
{
	CloseDevice((struct IORequest *)tr);
	DeleteExtIO((struct IORequest *)tr);
}

void DoTime(struct timerequest *tr, ULONG secs)
{
	tv.tv_secs=secs/10;
	tv.tv_micro=100000*(secs-tv.tv_secs*10);
	tr->tr_time=tv;
	tr->tr_node.io_Command=TR_ADDREQUEST;
	SendIO((struct IORequest *)tr);
}

void DisplayString(int x, int y, char *txt)
{
int l;
	Move(rp,(x<<3),((y<<3)+7));
	l=strlen(txt);
	if ((l+x)>=78) {
		Text(rp,txt,78-x);
		y++;
		Move(rp,0,(y+1)<<8+7);
		Text(rp,&txt[78-x],l+x-78);
		x+=l-78;
	}
	else {
		Text(rp,txt,l);
		x+=l;
	}
}

void DisplayChar(int x, int y, char c)
{
	Move(rp,(x<<3),((y<<3)+7));
	Text(rp,&c,1L);
}

void ToProto(char *str)
{
FILE *f;
long t;
	if (f=fopen(protokoll,"a")) {
		fputs(str,f);
		time(&t);
		fputs(ctime(&t),f);
		fclose(f);
	}
}


