#include "ucall.h"


UBYTE  *read_buffer;
UBYTE  *file_buffer;
UBYTE  *last_line;
UBYTE  *ct;
UBYTE  *rcbuffer;
UBYTE  *bf;
UBYTE  *sendfilebuffer;
UBYTE  *pb;

UBYTE  chr_buffer[MAX_BREAKCHARS];
UBYTE  pattern_buffer[MAX_BREAKCHARS][BUFFER_SIZE_PATTERN];

struct Library *LocaleBase;

UBYTE  *uc_strings[] =
        {
         "(0)  UCall : Konfigfile %s nicht gefunden\n",
         "(1)  USAGE : UCall Configfile Loginscript\n",
         "(2)  UCall: %s ist kein UCall-Configfile !\n",
         "(3)  UCall: Fehler im Configfile: %s\n",
         "(4)  UCall: Konnte Metaxpr.library nicht öffnen !\n",
         "(5)  UCall: Konnte timer.device nicht öffnen !\n",
         "(6)  UCall: Konnte <%s> Unit %ld nicht öffnen !\n",
         "(7)  UCall: Konnte MessagePort nicht öffnen !\n",
         "(8)  UCall: Loginscript %s nicht gefunden\n",
         " Programmabbruch durch Control-C\n",
         "(10) UCALL: Sendfile %s konnte nocht geöffnet werden\n",
         "(11) UCALL: Sendfile %s nicht gefunden\n",
         "(12) UCALL: Abbruch wegen Speichermangel !\n",
         "(13) SetFlag : Gültige Flags sind 8-31 !\n",
         "(14) GOSUB-Sprungziel %s nicht gefunden\n",
         "(15) RETURN ohne GOSUB gefunden !\n",
         "(16) GOTO-Sprungziel %s nicht gefunden\n",
         "(17) UCall : Anwahlversuch %s\n",
         "(18) UCall : Besetzt !\n",
         "(19) UCall : No Carrier  !\n",
         "(20) UCall : Kein Freizeichen !\n",
         "(21) **Warte noch %ld Sekunden **\r",
         "(22) File nicht gefunden",
         "(23) UCall-Setup: Nicht genügend Speicher !!\n",
         " Programmabbruch durch Timeout-Error\n",
         
        };

UBYTE *monate[] =
       {
        "Januar","Februar","März","April","Mai","Juni","Juli","August","September",
        "Oktober","November","Dezember",NULL,
       };

UBYTE *tage[] =
       {
        "Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag",
       };


ULONG flags;

struct params usr_vars[] = 
       {
        "$linebuffer" ,V_LBSIZE,
        "$ok"         ,V_OK,
        "$error"      ,V_ERROR,
        "$connect"    ,V_CONNECT,
        "$nocarrier"  ,V_NOCARRIER,
        "$nodialtone" ,V_NODIALTONE,
        "$device"     ,V_DEVICE,
        "$delayed"    ,V_DELAYED,
        "$xprlib"     ,V_XPRLIB,
        "$xpropts"    ,V_XPROPTS,
        "$busy"       ,V_BUSY,
        "$buffersize" ,V_BUFFER,
        "$baud"       ,V_BAUD,
        "$unit"       ,V_UNIT,
        "$databits"   ,V_DATABITS,
        "$stopbits"   ,V_STOPBITS,
        "$parity"     ,V_PARITY,
        "$line"       ,V_LINE,
        "$date"       ,V_DATE,
        "$time"       ,V_TIME,
        "$config"     ,V_CONFIG,
        "$script"     ,V_SCRIPT,
        "$fileinfo"   ,V_FILEINFO,
        "$handshake"  ,V_HANDSHAKE,
        "$filename"   ,V_FILENAME,
        "$filesize"   ,V_FILESIZE,
        NULL,
       };
       
struct user_param usr =
       {
        {"ucall.config"},
        {"ucall.login"},
        {"CONNECT"},
        {"serial.device"},
        {"NO CARRIER"},
        {"BUSY"},
        {"NO DIALTONE"},
        {"DELAYED"},
        {"ERROR"},
        {"OK"},
        {"xprzmodem.device"},
        {" "},
        {8},
        {0},
        {1},
        {0},
        {0},
        {19200},
        {8192},
        {1024},
       };
       
struct MsgPort  *serport;
struct MsgPort  *TimerPort;
struct IOExtSer *serial_req_read;
struct IOExtSer *serial_req_write;
struct IOExtSer *serial_req_cmd;
struct Library  *TimerBase;
struct Locale   *loc;
struct Catalog  *cat;
UWORD  serial_dever = TRUE;
UWORD  timer_dev    = TRUE;
UBYTE  global_flag;
ULONG  global_timeout = 180;
ULONG  global_repeat  = 120;
struct timerequest *tr;
struct List script;
struct List return_stack;
struct List vars;
struct List extramem;
ULONG global_timer = 0;
struct Library *metaxprbase;
BPTR   oldlock;
BPTR   showlog;
FILE  *protfile;
UBYTE  ser_openflags = (SERF_7WIRE | SERF_SHARED);
UBYTE  ser_flags     = (SERF_XDISABLED); 
struct Node *script_node;
struct Node *timeout_label;
int readbytes;
struct timeval     datum;
struct ClockData   cd;
UBYTE  *bfp;

struct Hook localedatehook =
       {
       	{NULL, NULL},
       	(void *)locale_date_func,
	       NULL, NULL
       };

struct params names[] = 
       {
        "DEVICE"     ,P_DEVICE,
        "UNIT"       ,P_UNIT,
        "BAUD"       ,P_BAUD,
        "BUSY"       ,P_BUSY,
        "NOCARRIER"  ,P_NOCARRIER,
        "NODIALTONE" ,P_NODIALTONE,
        "DELAYED"    ,P_DELAYED,
        "ERROR"      ,P_ERROR,
        "CONNECT"    ,P_CONNECT,
        "XPRLIB"     ,P_XPRLIB,
        "XPROPTS"    ,P_XPROPT,
        "DATENBITS"  ,P_DATABITS,
        "PARITY"     ,P_PARITY,
        "STOPBITS"   ,P_STOPBITS,
        "RTS/CTS"    ,P_RTS,
        "XON/OFF"    ,P_XON,
        "BUFFER"     ,P_BUFFER,
        "OK"         ,P_OK,
        NULL,0
    };
        
struct params cmds[] =
       {
        "SENDFILE"   ,C_TEXTFILE,
        "SETENV"     ,C_SETENV,
        "GETENV"     ,C_GETENV,
        "IFVAR"      ,C_IFVAR,  
        "SETFLAG"    ,C_SETFLAG,
        "CLEARFLAG"  ,C_CLEARFLAG,
        "IFFLAG"     ,C_IFFLAG,   
        "CONNECT"    ,C_WCONNECT,
        "CRLF"       ,C_CRLF,
        "SEND"       ,C_SEND,
        "WAIT"       ,C_WAIT,
        "MSG"        ,C_MSG,
        "PUTFILE"    ,C_SENDFILE,
        "GETFILE"    ,C_GETFILE,
        ";"          ,C_COMMENT,  
        "SHOWLOGIN"  ,C_SHLOG,
        "TIMEOUT"    ,C_TIMEOUT,
        "PAUSE"      ,C_REPEAT,
        "SYSTEM"     ,C_SYSTEM,
        "WORKDIR"    ,C_WORKDIR,
        "GOTO"       ,C_GOTO,
        LABEL_STRING ,C_LABEL,
        "IF"         ,C_IF,
        "END"        ,C_END,
        "GOSUB"      ,C_GOSUB,
        "RETURN"     ,C_RETURN,
        "TIMEOUT_LABEL",C_TIMELABEL,
        "PROTOCOL"   ,C_PROTOCOL,
        "PROTMSG"    ,C_PROTMSG,
        "SET"        ,C_SET,
        "RESETLINE"  ,C_RESETLINE,
        "LINEBUFFER" ,C_LBSIZE,
        "DELAY"      ,C_DELAY,
        NULL,0
       };
       
UBYTE *zcversion = ZC_VERSION;

void __stdargs main(int argc, char *argv[])
{
 NewList(&script);
 NewList(&return_stack);
 NewList(&vars);
 NewList(&extramem);
 getlocale();
 oldlock = Lock("",SHARED_LOCK);
 Printf("\x1b[2m%s\x1b[0m\n",zcversion);
 Printf("Freeware by Lunqual%%mab@wsb.freinet.de\n\n");
 if(argc == 3)
 {
  strcpy(usr.cfgfile,argv[1]);
  strcpy(usr.script,argv[2]);
  if(rcbuffer = (UBYTE *)AllocVec(usr.lbsize,MEMF_ANY | MEMF_CLEAR))
  {
   if(readconfig(argv[1]))
   {
    if(ser_setup())
    {
     if(readscript(argv[2]))
     {
      makecall();
     }
    }
    ser_cleanup(0);
   }    
  }
 }
 else  Printf(GETSTR(1));
 releaselocale();
 exit(0);
}



int __regargs readconfig(UBYTE *filename)
{
 BOOL rc    = FALSE;
 BOOL begin = FALSE;
 FILE *file;
 if(file = fopen(filename,"r"))
 {
  rc = TRUE;
  while(fgets(rcbuffer,usr.lbsize,file))
  {
   if(IsZcConf(rcbuffer))
   {
    if(!begin)
    {
     begin = TRUE;
    }
    else break;
   }
   {
    ULONG cl;
    if(begin)
    {
     cl = checkline(rcbuffer);
     if(cl)parseline(rcbuffer,cl);
    }
   }
  }
  if((rc)&&(!begin)){Printf(GETSTR(3),filename);rc = FALSE;}
  fclose(file);
 }
 else Printf(GETSTR(0),filename);
 return rc;
}

void __regargs parseline(UBYTE *buffer,ULONG what)
{
 UBYTE *p = buffer;
 if(what)
 {
  BOOL found = FALSE;
  while(*p)
  {
   if(*p == '=')
   {
    p++;
    found = TRUE;
    break;
   }
   p++;
  }  
  if(found)
  {
   switch(what)
   {
    case P_BUFFER    : {
                        ULONG s;
                        if(isdigit(*p))
                        {
                         s = atol(p);
                         if(s >= 1024)usr.bufsize = s;
                        }
                       }
                       break;
    case P_CONNECT   : *(buffer + strlen(buffer) - 1) = 0;
                       strcpy(usr.connect,p);
                       break;
    case P_BUSY      : *(buffer + strlen(buffer) - 1) = 0;
                       strcpy(usr.busy,p);
                       break;
    case P_OK        : *(buffer + strlen(buffer) - 1) = 0;
                       strcpy(usr.ok,p);
                       break;
    case P_NOCARRIER : *(buffer + strlen(buffer) - 1) = 0;
                       strcpy(usr.nocarrier,p);
                       break;
    case P_NODIALTONE: *(buffer + strlen(buffer) - 1) = 0;
                       strcpy(usr.nodialtone,p);
                       break;
    case P_DEVICE    : *(buffer + strlen(buffer) - 1) = 0;
                       strcpy(usr.device,p);
                       break;
    case P_ERROR    : *(buffer + strlen(buffer) - 1) = 0;
                       strcpy(usr.error,p);
                       break;
    case P_UNIT      : if(isdigit(*p))usr.unit = atol(p);
                       break;
    case P_DELAYED   : *(buffer + strlen(buffer) - 1) = 0;
                       strcpy(usr.delayed,p);
    case P_XPRLIB    : *(buffer + strlen(buffer) - 1) = 0;
                       strcpy(usr.xprlib,p);
                       break;
    case P_XPROPT    : *(buffer + strlen(buffer) - 1) = 0;
                       strcpy(usr.xpropt,p);     
                       break;
    case P_BAUD      : if(isdigit(*p))usr.baud = atol(p);
                       break;
    case P_DATABITS  : if(isdigit(*p))
                       {
                        usr.data = (UBYTE)atol(p);
                        if((usr.data < 7 ) || (usr.data > 8))usr.data = 8;
                       }
                       break;
    case P_STOPBITS  : if(isdigit(*p))
                       {
                        usr.stop = (UBYTE)atol(p);
                        if((usr.stop < 0 ) || (usr.stop > 2))usr.data = 1;
                       }
                       break;
    case P_RTS       : ser_openflags = (SERF_7WIRE | SERF_SHARED);
                       ser_flags     = (SERF_XDISABLED);
                       usr.handshake = 0;
                       break;
    case P_XON       : ser_openflags = (SERF_SHARED);
                       ser_flags     = (0);
                       usr.handshake = 1;
                       break;
    case P_PARITY    : if(!strnicmp(p,"odd",strlen("odd")))
                       {
                        ser_flags |= (SERF_PARTY_ODD | SERF_PARTY_ON);
                        usr.parity = 2;   
                       }
                       else if(!strnicmp(p,"even",strlen("even")))
                       {
                        ser_flags |= (SERF_PARTY_ON);
                        usr.parity = 1;
                       }
                       break;
   }
  }
  else Printf(GETSTR(3),buffer);  
 }
}

ULONG __regargs checkline(UBYTE *buffer)
{
 ULONG i;
 ULONG rc = 0;
 if(*buffer > ' ')
 {
  for(i=0;names[i].text;i++)
  {
   if(!strnicmp(buffer,names[i].text,strlen(names[i].text)))
   {
    rc = names[i].n;
    break;
   }
  }
 }
 return rc;
}

int  __regargs IsZcConf(UBYTE *buffer)
{
 return (!strnicmp(buffer,UCALL_CONFIG,strlen(UCALL_CONFIG))) ? TRUE  : FALSE;
}

int ser_setup()
{
 int rc= FALSE;
 if(serport = CreateMsgPort())
 {
  if(serial_req_read = (struct IOExtSer *)CreateExtIO( serport, sizeof( struct IOExtSer )))
  {
   if(serial_req_write = (struct IOExtSer *)CreateExtIO( serport, sizeof( struct IOExtSer )))
   {
    if(serial_req_cmd = (struct IOExtSer *)CreateExtIO( serport, sizeof( struct IOExtSer )))
    {
     serial_req_read->io_SerFlags= ser_openflags;
     if(!(serial_dever = OpenDevice( usr.device, usr.unit, serial_req_read,0)))
     {
      CopyMem(serial_req_read,serial_req_write,sizeof(struct IOExtSer));
      CopyMem(serial_req_read,serial_req_cmd,sizeof(struct IOExtSer));
      {
       serial_req_cmd->io_RBufLen  = usr.bufsize;
       serial_req_cmd->io_Baud     = usr.baud;
       serial_req_cmd->io_BrkTime  = BREAK_TIME;  
       serial_req_cmd->io_ReadLen  = usr.data;
       serial_req_cmd->io_WriteLen = usr.data;
       serial_req_cmd->io_StopBits = usr.stop;
       serial_req_cmd->io_SerFlags = ser_flags;
       serial_req_cmd->io_ExtFlags = ADDITIONAL_FLAGS;
       serial_req_cmd->IOSer.io_Command = SDCMD_SETPARAMS;  
       DoIO( serial_req_cmd );
       {
        if(opentimerdevice())
        {
         TimerBase = (struct Library *)tr->tr_node.io_Device;
         if(metaxprbase = OpenLibrary("metaxpr.library",2))
         {
          if(getbuffers())
          {
           rc = TRUE;
          }
         }
         else Printf(GETSTR(4));
        }
        else Printf(GETSTR(5));
       }
      }
     }
     else Printf(GETSTR(6),usr.device,usr.unit);
    }
   }
  }
 }
 else Printf(GETSTR(7));
 return rc;
}

int opentimerdevice()
{
 if(TimerPort = CreateMsgPort())
 {
  if(tr = (struct timerequest *)CreateExtIO(TimerPort,sizeof(struct timerequest)))
  {
   if(timer_dev = OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)tr,0))
   {
    DeleteExtIO(tr);
    return FALSE;
   }
  }
 } 
 return TRUE;
}

void closetimerdevice()
{
 if((tr) && (!CheckIO(tr)))
 {
  AbortIO(tr);
  WaitIO(tr);
 }
 if(!timer_dev)CloseDevice(tr);
 if(tr)DeleteExtIO(tr);
 if(TimerPort)DeleteMsgPort(TimerPort);
}



void __regargs ser_cleanup(ULONG rc)
{
 struct Node *scr;
 if( serial_req_read && (!CheckIO(serial_req_read)))
 {
  AbortIO(serial_req_read);
  WaitIO(serial_req_read);
 }
 if( serial_req_write && (!CheckIO(serial_req_write)))
 {
  AbortIO(serial_req_write);
  WaitIO(serial_req_write);
 }
 if( serial_req_cmd && (!CheckIO(serial_req_cmd)))
 {
  AbortIO(serial_req_cmd);
  WaitIO(serial_req_cmd);
 }
 serial_req_cmd->IOSer.io_Command = CMD_RESET;  
 DoIO( serial_req_cmd );
 WaitIO(serial_req_cmd);
 if( !serial_dever )CloseDevice( serial_req_read );
 if(serial_req_read) DeleteExtIO( serial_req_read );
 if(serial_req_write) DeleteExtIO( serial_req_write );
 if(serial_req_cmd) DeleteExtIO( serial_req_cmd );
 if( serport )DeletePort(serport);
 closetimerdevice();
 while(scr = RemHead(&return_stack))
 {
  FreeVec(scr);
 }
 freebuffers();
 if(rc == CLEANUP_RESTART)
 {
  Delay(100);
  if(ser_setup())return;
 }
 while(scr = RemHead(&script))
 {
  if(scr->ln_Name)FreeVec(scr->ln_Name);
  FreeVec(scr);
 }
 {
  struct var_node *v;
  while(v = (struct var_node *)RemHead(&vars))
  {
   if(v->node.ln_Name)FreeVec(v->node.ln_Name);
   if(v->text)FreeVec(v->text);
   FreeVec(v);
  }
 }
 while(scr = RemHead(&extramem))
 {
  if(scr->ln_Name)FreeVec(scr->ln_Name);
  FreeVec(scr);
 }
 if(metaxprbase)CloseLibrary(metaxprbase);
 if(oldlock)
 {
  BPTR newlock;
  if(newlock = CurrentDir(oldlock))UnLock(newlock);
 }
 if(sendfilebuffer)FreeVec(sendfilebuffer);
 if(showlog)Close(showlog);
 if(protfile)fclose(protfile);
 if(rcbuffer)FreeVec(rcbuffer);
 releaselocale();
 exit(rc);
}


int __regargs read_line(UBYTE *buffer,UBYTE *chrs,UBYTE n)
{
 int rc = 1;
 UBYTE i;
 while(1)
 {
  int r;
  r = SerRead(serial_req_read,buffer + readbytes,1);
  if(!r)return 0;
  for(i = 0; i < n;i++)
  {
   if (*(buffer + readbytes) == *(chrs + i))
   {
    readbytes++;
    return 3;
   }
  }
  if(*(buffer + readbytes) == '\n')
  {
   readbytes = 0;
   memset(buffer,0,usr.lbsize);
   return 2;
  }
  readbytes++;if(readbytes >= usr.lbsize)readbytes = 0;
 }
 return rc;
}

int __regargs readscript(UBYTE *filename)
{
 int rc = TRUE;
 FILE *scr;
 struct Node *s;
 memset(read_buffer,0,usr.lbsize);
 if(scr = fopen(filename,"r"))
 {
  while(fgets(read_buffer,usr.lbsize,scr))
  {
   if((*read_buffer) && (*(read_buffer + strlen(read_buffer) - 1) == '\n'))*(read_buffer + strlen(read_buffer) - 1) = 0;
   if(*read_buffer)
   {
    if(s = (struct Node *)AllocVec(sizeof(struct Node),MEMF_ANY | MEMF_CLEAR))
    {
     if(s->ln_Name = AllocVec(strlen(read_buffer) + 10,MEMF_ANY | MEMF_CLEAR))
     {
      if(!strnicmp(read_buffer,LABEL_STRING,strlen(LABEL_STRING)))
      {
       UBYTE *p = read_buffer;
       if(*(read_buffer + strlen(read_buffer) - 1) == '\n')*(read_buffer + strlen(read_buffer) - 1) = 0;
       strcpy(s->ln_Name,LABELINTRO);
       while((*p) && (*p != ' ') && (*p != '\n'))p++;
       p = stpblk(p);
       strcat(s->ln_Name,p);
      }
      else strcpy(s->ln_Name,read_buffer);
      AddTail(&script,s);
     }
     else 
     {
      rc = FALSE;
      break;
     }
    } 
    else
    { 
     rc = FALSE;
    break;
    }
   }
   memset(read_buffer,0,usr.lbsize);
  }
  fclose(scr); 
 }
 else Printf(GETSTR(8),filename); 
 return rc;
}


UBYTE __regargs *skipeol(UBYTE *buffer)
{
 UBYTE *rc = buffer;
 while((*rc == '\r') || (*rc == '\n'))rc++;
 return rc;
}

int __regargs SerRead(struct IOExtSer *ioreq, BYTE *data, ULONG length)
{
 ULONG sigs;
 int rc;
 ioreq->IOSer.io_Command = CMD_READ;
 ioreq->IOSer.io_Data = (APTR) data;
 ioreq->IOSer.io_Length = length;
 SendIO( ioreq );
 sigs = Wait( (1L<<TimerPort->mp_SigBit) | (1L<<serport->mp_SigBit) | SIGBREAKF_CTRL_C);
 rc = check_sigs(sigs);
 if(showlog)FPutC(showlog,*data);
 return rc;
}


int __regargs SerWrite(struct IOExtSer *ioreq, BYTE *data, ULONG length)
{
 ULONG sigs;
 ioreq->IOSer.io_Command = CMD_WRITE;
 ioreq->IOSer.io_Data = (APTR) data;
 ioreq->IOSer.io_Length = length;
 SendIO( ioreq );
 sigs = Wait((1L<<serport->mp_SigBit) | SIGBREAKF_CTRL_C);
 if(sigs & SIGBREAKF_CTRL_C)
 {
  strcpy(bf,"(9) UCall :   ");
  maketime(bf + 13);
  strcat(bf,GETSTR(9));strcat(bf,"\n");
  Printf(bf);
  if(protfile)fputs(bf,protfile);
  ser_cleanup(RETURN_ABBRUCH);
 }
 return TRUE;
}


int makecall()
{
 int rc = FALSE;
 for ( script_node = script.lh_Head;script_node->ln_Succ;script_node = script_node->ln_Succ)
 {
  parsecomm(script_node->ln_Name);
 }
 return rc;
}

void __regargs parsecomm(UBYTE *c)
{
 int i;
 UBYTE *csource;
 memset(ct,0,usr.lbsize);
 for(i=0;cmds[i].text;i++)
 {
  if(!strnicmp(c,cmds[i].text,strlen(cmds[i].text)))
  {
   csource = c;
   while(*csource > ' ')csource++;
   csource = stpblk(csource);
   makestring(ct,csource);
   switch(cmds[i].n)
   {
    case C_TEXTFILE     : {
                           LONG size;
                           BPTR lock;
                           BPTR file;
                           UBYTE *p;
                           struct FileInfoBlock __aligned fib;
                           p = ct  + strlen(ct) - 1;
                           while((*p == ' ') || (*p == '\n') || (*p == '\r')){*p = 0;--p;}
                           if(lock = Lock(ct,ACCESS_READ))
                           {
                            Examine(lock,&fib);
                            size = fib.fib_Size;
                            UnLock(lock);
                            if(file = Open(ct,MODE_OLDFILE))
                            {
                             if(sendfilebuffer = AllocVec(size + 2,MEMF_ANY | MEMF_CLEAR))
                             {
                              if(Read(file,sendfilebuffer,size))
                              {
                               SerWrite(serial_req_write,sendfilebuffer,(ULONG)size);
                              }
                              FreeVec(sendfilebuffer);
                              sendfilebuffer = NULL;
                             }
                             Close(file);
                            }
                            else
                            {
                             Printf(GETSTR(10),ct);
                             UnLock(lock);
                            }
                           } else Printf(GETSTR(11),ct);
                          }
                          break;
    case C_SETENV       : if(*ct)
                          {
                           UBYTE *set,*var;
                           set = strtok(ct,"=");
                           if(set)
                           {
                            var = strtok(NULL,"=");
                            if(var)
                            {
                             UBYTE *s1;
                             for(s1 = set;*s1 && (s1 < var);s1++)
                             if(*s1 == ' ')*s1 = 0;
                             SetVar(set,var,-1,GVF_GLOBAL_ONLY);
                            }
                           }
                          }
                          break;
    case C_GETENV       : if(*ct)
                          {
                           UBYTE *get,*var,*vr;
                           struct var_node *vn;
                           var = bf;
                           *var = '$';*(var + 1) = 0;
                           vr = strtok(ct,"=");
                           if(vr)
                           {
                            strcat(var,vr);
                            get = strtok(NULL,"=");
                            if(get)
                            {
                             UBYTE *s1;
                             for(s1 = var;*s1;s1++)if(*s1 == ' ')*s1 = 0;
                             if(GetVar(get,file_buffer,usr.lbsize,0) > 0)
                             {
                              if(vn = (struct var_node *)FindName(&vars,var))
                              {
                               Remove(vn);
                               if(vn->node.ln_Name)FreeVec(vn->node.ln_Name);
                               if(vn->text)FreeVec(vn->text);
                               FreeVec(vn);
                              }
                              if(vn = (struct var_node *)AllocVec(sizeof(struct var_node),MEMF_ANY | MEMF_CLEAR))
                              {
                               if(vn->node.ln_Name = AllocVec(strlen(var) + 10,MEMF_ANY | MEMF_CLEAR))
                               {
                                if(vn->text = AllocVec(strlen(file_buffer) + 10, MEMF_ANY | MEMF_CLEAR))
                                {
                                 strcpy(vn->node.ln_Name,var);
                                 strcpy(vn->text,file_buffer);
                                 AddHead(&vars,(struct Node *)vn);
                                }
                               }
                              }
                             }
                            }
                           }
                          }
                          break;                      
    case C_IFVAR        : {
                           UBYTE *var,*value,*c;
                           if(var = strtok(ct,","))
                           {
                            if(value = strtok(NULL,","))
                            {
                             value = stpblk(value);
                             if(c = strtok(NULL,","))
                             {
                              c = stpblk(c);
                              ParsePatternNoCase(value,pb,usr.lbsize);
                              if(MatchPatternNoCase(pb,var))
                              if(*c)multiple_if(c);
                             }
                            }
                           }
                          }                      
                          break;
    case C_DELAY        : if((*ct) && (isdigit(*ct)))
                          {
                           ULONG v = atol(ct);
                           if(v > 1)
                           {
                            timerdelay(v);
                           }
                          }
                          else timerdelay(global_repeat);
                          break;
    case C_LBSIZE       : if(isdigit(*ct))
                          {
                           ULONG size = atol(ct);
                           if(size > 511)
                           {
                            freebuffers();
                            usr.lbsize = size;
                            if(!getbuffers())
                            {
                             Printf(GETSTR(12));
                             ser_cleanup(RETURN_ABBRUCH);
                            }
                           }
                          }
                          break;
    case C_RESETLINE    : readbytes = 0;
                          serial_req_cmd->IOSer.io_Command = CMD_CLEAR;  
                          DoIO( serial_req_cmd );
                          break;
    case C_SET          : {
                           struct var_node *v;
                           UBYTE *c;
                           c = strtok(ct,"=");
                           if(c)
                           {
                            c = strtok(NULL,"=");
                            if(c)
                            {
                             if(v = (struct var_node *)AllocVec(sizeof(struct var_node),MEMF_ANY | MEMF_CLEAR))
                             {
                              if(v->node.ln_Name = AllocVec(strlen(ct) + 10,MEMF_ANY | MEMF_CLEAR))
                              {
                               if(v->text = AllocVec(strlen(c) + 10,MEMF_ANY | MEMF_CLEAR))
                               {
                                UBYTE *s = ct;
                                UBYTE *d = v->node.ln_Name + 1;
                                *(v->node.ln_Name) = '$';
                                while(1)
                                {
                                 *d++ = *s++;
                                 if((!(*s)) || (s == c) || (*s == ' ') )break;
                                }
                                strcpy(v->text,c);
                                AddHead(&vars,(struct Node *)v);
                               }
                              }
                              else
                              {
                               FreeVec(v);
                              }
                             }
                            }
                           }
                          }
                          break;
    case C_PROTMSG      : if(protfile)fputs(ct,protfile);
                          break;
    case C_PROTOCOL     : {
                           UBYTE *name;
                           if(protfile)
                           {
                            fclose(protfile);
                           }
                           if(*ct)name = ct;
                           else  name = "ucall.protocol";
                           protfile = fopen(name,"a");
                          }
                          break;
    case C_SETFLAG      : {
                           ULONG n;
                           if(isdigit(*ct))
                           {
                            n = atol(ct);
                            if((n > 7) && (n < 32))
                            {
                             flags |= (1 << n);
                            }
                            else Printf(GETSTR(13));
                           }
                          }
                          break;
    case C_CLEARFLAG     : {
                           ULONG n;
                           if(isdigit(*ct))
                           {
                            n = atol(ct);
                            if((n >= 0) && (n < 32))
                            {
                             if(flags & (1 << n))flags ^= (1 << n);
                            }
                           }
                          }
                          break;  
    case C_IFFLAG       : {
                           ULONG n;
                           if(isdigit(*ct))
                           {
                            n = atol(ct);
                            if((n >= 0) && (n < 32))
                            {
                             if(flags & (1 << n))
                             {
                              UBYTE *next;
                              for(next = ct;((*next) &&(*next != ' '));next++);
                              next = stpblk(next);
                              if(*next)multiple_if(next);
                             }
                            }
                           }
                          }
                          break;                     
    case C_TIMELABEL    : timeout_label = script_node;
                          break;
    case C_GOSUB        : {
                           struct Node *node;
                           struct r_node *ret;
                           strcpy(bf,LABELINTRO);
                           strncat(bf,ct,usr.lbsize);
                           if(node = FindName(&script,bf))
                           {
                            if(ret = (struct r_node *)AllocVec(sizeof(struct r_node),MEMF_ANY | MEMF_CLEAR))
                            {
                             ret->ziel = script_node;
                             AddHead(&return_stack,(struct Node *)ret);
                             script_node = node;
                            }
                           }
                           else Printf(GETSTR(14),bf);
                          } 
                          break;
    case C_RETURN       : {
                           struct r_node *node;
                           if(node = (struct r_node *)RemHead(&return_stack))
                           {
                            script_node = node->ziel;
                            FreeVec(node);
                           }
                           else Printf(GETSTR(15));
                          }
                          break;
    case C_IF           : {
                           UBYTE *next;
                           for(next = ct;((*next) &&(*next != ' '));next++);
                           {
                            *next = 0;
                            ParsePatternNoCase(ct,pb,usr.lbsize);
                            next++;
                            if(MatchPatternNoCase(pb,last_line))
                            {
                             if(*next)multiple_if(next);
                            }
                           }
                          }
                          break;
    case C_LABEL        : break;
    case C_GOTO         : {
                           struct Node *node;
                           strcpy(bf,LABELINTRO);
                           strncat(bf,ct,usr.lbsize);
                           if(node = FindName(&script,bf))script_node = node;
                           else Printf(GETSTR(16),bf);
                          } 
                          break;
    case C_END          : ser_cleanup(0);
                          break;
    case C_REPEAT       : if(isdigit(*ct))global_repeat = atol(ct);
                          break;
    case C_TIMEOUT      : if(isdigit(*ct))global_timeout = atol(ct);
                          break;
    case C_SHLOG        : {
                           if(*ct)
                           {
                            if(!showlog)
                            {
                             showlog = Open(ct,MODE_NEWFILE);
                            }
                           }
                           else
                           {
                            if(!showlog)
                            {
                             showlog=Open("con:0/0/640/480/UCall: Login",MODE_NEWFILE);
                            }
                           }
                          }
                          break;
    case C_WCONNECT     : {
                           UBYTE *eol;
                           while(1)
                           {
                            Printf(GETSTR(17),ct);
                            SerWrite(serial_req_write,ct,-1);
                            sprintf(bf,"%s,%s,%s,%s",usr.connect,usr.busy,usr.nocarrier,usr.nodialtone);
                            waitstring(bf);
                            eol = read_buffer;
                            if(!strnicmp(eol,usr.connect,strlen(usr.connect)))
                            {
                             Printf("UCall : %s\n",eol);
                             break;
                            }
                            else
                            if(!strnicmp(eol,usr.busy,strlen(usr.busy)))
                            {
                             Printf(GETSTR(18));
                             timerdelay(global_repeat);
                            }
                            else
                            if(!strnicmp(eol,usr.nocarrier,strlen(usr.nocarrier)))
                            {
                             Printf(GETSTR(19));
                             timerdelay(global_repeat);
                            }
                            else
                            if(!strnicmp(eol,usr.nodialtone,strlen(usr.nodialtone)))
                            {
                             Printf(GETSTR(20));
                             timerdelay(global_repeat);
                            }
                           }
                          }
                          break; 
                          
    case C_WAIT       : timeout_start(global_timeout);
                        waitstring(ct);
                        timeout_end();
                        break;
    case C_SEND       : SerWrite(serial_req_write,ct,-1);
                        break;
    case C_CRLF       : SerWrite(serial_req_write,"\r\n",-1);
                        break;
    case C_MSG        : fputs(ct,stdout);fflush(stdout);
                        break;
    case C_COMMENT    : break;
    case C_SENDFILE   : {
                         timeout_end();
                         TransferSetupShared(serial_req_read,serial_req_write,usr.xprlib);
                         SetOptions(usr.xpropt);
                         strcpy(read_buffer,ct);
                         if(!SendFile(read_buffer,2,NULL))flags |= (1<<FLAG_UPLOAD);
                         strcpy(file_buffer,read_buffer);
                        }
                        /* File senden ! */
                        break;
    case C_GETFILE    : {
                         timeout_end();
                         TransferSetupShared(serial_req_read,serial_req_write,usr.xprlib);
                         SetOptions(usr.xpropt);
                         strcpy(read_buffer,ct);
                         if(!ReceiveFile(read_buffer,2,NULL))flags |= (1<<FLAG_DOWNLOAD);
                         strcpy(file_buffer,read_buffer);
                        }
                        /* file holen */
                        break;
    case C_SYSTEM     : System(ct,TAG_DONE);
                        break;
    case C_WORKDIR    : {
                         BPTR lock,cd;
                         if(lock = Lock(ct,SHARED_LOCK))
                         {
                          cd = CurrentDir(lock);
                          UnLock(cd);
                         }
                        }
                        break;
    default           : break;                   
   }
   break;
  }
 }
}


void __regargs waitstring(UBYTE *string)
{
 UBYTE i = 0;
 UBYTE j;
 UBYTE *eol,*tmp;
 readbytes = 0; 
 memset(read_buffer,0,usr.lbsize);
 tmp = strtok(string,",");
 while(tmp)
 {
  *(chr_buffer + i) = *(tmp + strlen(tmp) -1);
  ParsePatternNoCase(tmp,pattern_buffer[i],BUFFER_SIZE_PATTERN);
  tmp = strtok(NULL,",");
  i++;
  if(i >= MAX_BREAKCHARS)break;
 }
 while(1)
 {
  int r;
  r = read_line(read_buffer,chr_buffer,i);
  if(!r)return;
  else 
  if (r == 3);
  {
   eol = skipeol(read_buffer);
   for(j = 0 ; j < i ; j++)
   {
    if(MatchPatternNoCase(pattern_buffer[j],eol))
    {
     strcpy(last_line,eol);
     for(j = 0 ; j < i ; j++)memset(pattern_buffer[j],0,BUFFER_SIZE_PATTERN);
     return;
    }
   }                           
  }
 } 
}

void __regargs makestring(UBYTE *dest,UBYTE *source)
{
 UBYTE *s,*d;
 long n;
 d = dest;
 s = source;  
 while(*d = *s)
 {
  if(*s == '\\')
  {
   s++;
   if(*s == 'n'){*d = '\n';d++;s++;}
   if(*s == 'r'){*d = '\r';d++;s++;}
   if((*s == 'x') || (*s == 'X'))
   {
    s++;
    s +=  stch_l(s,&n);--s;
    *d = (UBYTE)n;
   }
  }
  if (*s == '$')
  {
   ULONG i;
   struct Node *n;
   struct var_node *found = NULL;
   for(n = vars.lh_Head;n->ln_Succ;n = n->ln_Succ)
   {
    if(!strnicmp(s,n->ln_Name,strlen(n->ln_Name)))
    {
     found = (struct var_node *)n;
     break;
    }
   }
   if(!found)
   for(i=0;usr_vars[i].text;i++)
   {
    if(!strnicmp(s,usr_vars[i].text,strlen(usr_vars[i].text)))
    {
     var_x(&d,&s,i);
     break;
    }
   }
   else
   {
    strncpy(d,found->text,usr.lbsize);
    d += strlen(found->text) - 1 ;
    s += strlen(found->node.ln_Name) - 1;
   }
  }
  d++;s++;
 }
}

void timeout_end()
{
 if(!CheckIO(tr))
 {
  AbortIO(tr);
  WaitIO(tr);
 }
}

void __regargs timeout_start(ULONG sec)
{
 timeout_end();
 tr->tr_node.io_Command = TR_ADDREQUEST;
 tr->tr_time.tv_secs = sec;
 tr->tr_time.tv_micro = 0;
 SendIO(tr);   
}

void __regargs timerdelay(ULONG sec)
{
 ULONG sigs;
 int i;
 if(!CheckIO(tr))
 {
  AbortIO(tr);
  WaitIO(tr);
 }
 for(i = sec;i > 0;i--)
 {
  tr->tr_node.io_Command = TR_ADDREQUEST;
  tr->tr_time.tv_secs = 1;
  tr->tr_time.tv_micro = 0;
  SendIO(tr);
  {Printf(GETSTR(21),i);fflush(stdout);}
  sigs = Wait( (1L<<TimerPort->mp_SigBit) | SIGBREAKF_CTRL_C);
  if(sigs & SIGBREAKF_CTRL_C)
  {
   strcpy(bf,"(9) UCall :   ");
   maketime(bf + 13);
   strcat(bf,GETSTR(9));strcat(bf,"\n");
   Printf(bf);
   if(protfile)fputs(bf,protfile);
   ser_cleanup(RETURN_ABBRUCH); 
  }
  if(sigs & (1L<<TimerPort->mp_SigBit))GetMsg(TimerPort);
 }
}

void var_x(UBYTE **d,UBYTE **s,ULONG what)
{
 UBYTE *s1;
 ULONG w = usr_vars[what].n;
 switch(w)
 {
  case V_OK            : s1 = usr.ok;           break;
  case V_ERROR         : s1 = usr.error;        break;
  case V_CONNECT       : s1 = usr.connect;      break;
  case V_NOCARRIER     : s1 = usr.nocarrier;    break;
  case V_NODIALTONE    : s1 = usr.nodialtone;   break;
  case V_DEVICE        : s1 = usr.device;       break;
  case V_DELAYED       : s1 = usr.delayed;      break;
  case V_XPRLIB        : s1 = usr.xprlib;       break;
  case V_XPROPTS       : s1 = usr.xpropt;       break;
  case V_BUSY          : s1 = usr.busy;         break;
  case V_LBSIZE        : sprintf(bf,"%ld",usr.lbsize); s1 = bf; break;
  case V_BUFFER        : sprintf(bf,"%ld",usr.bufsize); s1 = bf; break;
  case V_BAUD          : sprintf(bf,"%ld",usr.baud); s1 = bf; break;
  case V_UNIT          : sprintf(bf,"%ld",usr.unit); s1 = bf; break;
  case V_DATABITS      : sprintf(bf,"%d",usr.data); s1 = bf; break;
  case V_STOPBITS      : sprintf(bf,"%d",usr.stop); s1 = bf; break;
  case V_PARITY        : sprintf(bf,"%s",(usr.parity == 0) ? "NONE" : (usr.parity == 1) ? "EVEN" : "ODD"); s1 = bf; break;  
  case V_HANDSHAKE     : sprintf(bf,"%s",(usr.handshake == 0) ? "RTS/CTS" : "XON/XOFF");s1 = bf; break;
  case V_LINE          : s1 = read_buffer; break;
  case V_CONFIG        : s1 = usr.cfgfile; break;
  case V_SCRIPT        : s1 = usr.script;  break;
  case V_FILENAME      : s1 = file_buffer;
                         break;
  case V_FILESIZE      : s1 = bf;
                         {
                          BPTR lock;
                          struct FileInfoBlock __aligned fib;
                          if(lock = Lock(file_buffer,ACCESS_READ))
                          {
                           Examine(lock,&fib);
                           sprintf(bf,"%ld",fib.fib_Size);
                           UnLock(lock);
                          }
                          else strcpy(bf,GETSTR(22));
                         }
                         break;
  case V_FILEINFO      : s1 = bf;
                         {
                          BPTR lock;
                          struct FileInfoBlock __aligned fib;
                          if(lock = Lock(file_buffer,ACCESS_READ))
                          {
                           Examine(lock,&fib);
                           sprintf(bf,"%s %ld Bytes",fib.fib_FileName,fib.fib_Size);
                           UnLock(lock);
                          }
                          else strcpy(bf,GETSTR(22));
                         }
                         break;
  case V_TIME          : {
                          maketime(bf);
                          s1 = bf;
                         }
                         break;
  case V_DATE          : {
                          struct DateStamp dst;
                          GetSysTime(&datum);
                          Amiga2Date(datum.tv_secs,&cd);
                          if(LocaleBase)
                          {
                           bfp = bf;
                           DateStamp(&dst); 
                           FormatDate(loc,loc->loc_DateFormat,&dst,&localedatehook);
                          }
                          else
                          sprintf(bf,"%s %d-%s-%d",
                                  tage[cd.wday],
                                  cd.mday,
                                  monate[cd.month-1],
                                  cd.year);

                          s1 = bf;
                         }
                         break;
  default              : return;                    
 }
 while(*(*d)++ = *s1++);(*d) -= 2;(*s) += strlen(usr_vars[what].text) - 1;
}

int getbuffers()
{
 if(read_buffer = (UBYTE *)AllocVec(usr.lbsize,MEMF_ANY | MEMF_CLEAR))
 {
  if(file_buffer = (UBYTE *)AllocVec(usr.lbsize,MEMF_ANY | MEMF_CLEAR))
  {
   if(last_line  = (UBYTE *)AllocVec(usr.lbsize,MEMF_ANY | MEMF_CLEAR))
   {
    if(ct  = (UBYTE *)AllocVec(usr.lbsize,MEMF_ANY | MEMF_CLEAR))
    {
     if(bf  = (UBYTE *)AllocVec(usr.lbsize,MEMF_ANY | MEMF_CLEAR))
     {
      if(pb = (UBYTE *)AllocVec(usr.lbsize,MEMF_ANY | MEMF_CLEAR))
      {
       return TRUE;   
      }
     }
    } 
   } 
  }
 }
 Printf(GETSTR(23));
 return FALSE;
}

void freebuffers()
{
 if(last_line){FreeVec(last_line);last_line = NULL;}
 if(read_buffer){FreeVec(read_buffer);read_buffer = NULL;}
 if(ct){FreeVec(ct);ct = NULL;}
 if(bf){FreeVec(bf);bf = NULL;}
 if(file_buffer){FreeVec(file_buffer);file_buffer = NULL;}
 if(pb){FreeVec(pb);pb = NULL;}
}

void multiple_if(UBYTE *line)
{
 struct Node *node;
 UBYTE *np;
 if(node = (struct Node *)AllocVec(sizeof(struct Node),MEMF_ANY | MEMF_CLEAR))
 { 
  if(node->ln_Name = AllocVec(usr.lbsize,MEMF_ANY | MEMF_CLEAR))
  {
   AddHead(&extramem,node);
   CopyMem(line,node->ln_Name,usr.lbsize);
   np = strtok(node->ln_Name,",");
   while(np)
   {
    parsecomm(np);
    np = strtok(NULL,",");
   }
   if(node = RemHead(&extramem))
   {
    if(node->ln_Name)FreeVec(node->ln_Name);
    FreeVec(node);
   }
  }
 }
}

int check_sigs(ULONG sigs)
{
 if(sigs & SIGBREAKF_CTRL_C)
 {
  strcpy(bf,"(9) UCall :    ");
  maketime(bf + 13);
  strcat(bf,GETSTR(9));strcat(bf,"\n");
  Printf(bf);
  if(protfile)fputs(bf,protfile);
  ser_cleanup(RETURN_ABBRUCH);
 }
 if(sigs & (1L<<TimerPort->mp_SigBit))
 {
  if(GetMsg(TimerPort))
  {
   if(timeout_label)
   {
    ser_cleanup(CLEANUP_RESTART);
    script_node = timeout_label;
    flags |= (1<<FLAG_TIMEOUT);
    return FALSE;
   }
   else
   {
    strcpy(bf,"(24) UCall :   ");
    maketime(bf + 13);
    strcat(bf,GETSTR(24));strcat(bf,"\n");
    Printf(bf);
    if(protfile)fputs(bf,protfile);
    ser_cleanup(RETURN_ABBRUCH);
   }
  }
 }
 return TRUE;
}

void    getlocale()
{
 if(LocaleBase = OpenLibrary("locale.library",38))
 {
  loc = OpenLocale(NULL);
  cat = OpenCatalog(loc,"ucall.catalog",OC_BuiltInLanguage,"deutsch",OC_Version,1,TAG_DONE);
 }
}

void releaselocale()
{
 if(cat)
 {
  CloseCatalog(cat);
  cat = NULL;
 }
 if(loc)
 {
  CloseLocale(loc);
  loc = NULL;
 }
 if(LocaleBase){CloseLibrary(LocaleBase);LocaleBase = NULL;}
}

void __asm __saveds locale_date_func(register __a1 UBYTE chr)
{
 *bfp++ = chr;
}

void maketime(UBYTE *to)
{
 struct DateStamp dst;
 GetSysTime(&datum);
 Amiga2Date(datum.tv_secs,&cd);
 if(LocaleBase)
 {
  bfp = to;
  DateStamp(&dst); 
  FormatDate(loc,loc->loc_TimeFormat,&dst,&localedatehook);
 }
 else
 sprintf(to,"(%02d:%02d:%02d) ",
             cd.hour,
             cd.min,
             cd.sec);
}
