/** xprfuncs.c
*
*   Call-back functions for eXternal PRotocol support
*
**/
#include <exec/types.h>
#include <exec/io.h>
#include <proto/exec.h>
#include <libraries/dos.h>
#include <proto/dos.h>
#include <devices/serial.h>
#include <devices/timer.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <dlg/dlgproto.h>
#include <dlg/file.h>
#include <dlg/user.h>

#include <link/file.h>
#include <link/io.h>

#include <proto/dlg.h>
#include "xproto.h"

#include <pragmas/dlg.h>

BOOL CarrierDetect(void);
BOOL cd(char *);

void debug(char *);


LONG __stdargs __saveds __asm xpr_update(register __a0 struct XPR_UPDATE *);
LONG __stdargs __saveds __asm xpr_gets(register __a0 char *,register __a1 char *);
LONG __stdargs __saveds __asm xpr_setserial(register __d0 long);
LONG __stdargs __saveds __asm xpr_swrite(register __a0 char *,register __d0 long);
LONG __stdargs __saveds __asm xpr_sread(register __a0 UBYTE *,register __d0 long, register __d1 long);
LONG __stdargs __saveds       xpr_sflush(void);
LONG __stdargs __saveds __asm xpr_fopen(register __a0 char *,register __a1 char *);
LONG __stdargs __saveds __asm xpr_fclose(register __a0 FILE *);
LONG __stdargs __saveds __asm xpr_fread(register __a0 char *,register __d0 long,  register __d1 long,register __a1 FILE *);
LONG __stdargs __saveds __asm xpr_fwrite(register __a0 char *,register __d0 long, register __d1 long,register __a1 FILE *);
LONG __stdargs __saveds __asm xpr_fseek(register __a0 FILE *,register __d0 long,  register __d1 long);
LONG __stdargs __saveds __asm xpr_ffirst(register __a0 char *,register __a1 char *);
LONG __stdargs __saveds __asm xpr_fnext(register __d0 long,register __a0 char *, register __a1 char *);
LONG __stdargs __saveds       xpr_chkabort(void);
LONG __stdargs __saveds       xpr_chkmisc(void);
LONG __stdargs __saveds __asm xpr_finfo(register __a0 char *,register __d0 long);

extern char              **SA;
extern struct Library     *DLGBase;

extern struct DLGSerInfo  *dsi;
extern struct timerequest *Timer;
extern struct MsgPort     *Timer_Port;
extern struct USER_DATA    UserDat;
extern struct Ram_File     RStruct;
 
extern BOOL          quiet;
extern BOOL          batchmode;
extern char         *batchfile;
extern char          tempdownloads[];
extern char          destfile[];
extern char          mydevice[];
extern char          tmode;

struct SearchCookie *sc        = NULL;
struct Batch         MyBatch;

BOOL                 abortflag = FALSE;
int                  filesopen = 0;
char                 fname[16];
ULONG                fsize     = 0;
long                 bytes     = 0;
long                 bsize     = 0;
long                 drate     = 0;

#define READSER_SIG (1 << dsi->read->IOSer.io_Message.mn_ReplyPort->mp_SigBit)
#define TIMER_SIG   (1 << Timer_Port->mp_SigBit)

/**
*
*   This function initializes an XPR_IO structure.
*
**/
BOOL xpr_setup(struct XPR_IO *IO)

{IO->xpr_filename  = NULL;

 /* NULL out all the functions we don't do. */
 IO->xpr_fopen     = (long (*)())xpr_fopen;
 IO->xpr_fclose    = (long (*)())xpr_fclose;
 IO->xpr_fread     = (long (*)())xpr_fread;
 IO->xpr_fwrite    = (long (*)())xpr_fwrite;
 IO->xpr_sread     = (long (*)())xpr_sread;
 IO->xpr_swrite    = (long (*)())xpr_swrite;
 IO->xpr_sflush    = (long (*)())xpr_sflush;
 IO->xpr_update    = (long (*)())xpr_update;
 IO->xpr_chkabort  = (long (*)())xpr_chkabort;
 IO->xpr_chkmisc   = (long (*)())xpr_chkmisc;
 IO->xpr_gets      = (long (*)())xpr_gets;
 IO->xpr_setserial = (long (*)())xpr_setserial;
 IO->xpr_ffirst    = (long (*)())xpr_ffirst;
 IO->xpr_fnext     = (long (*)())xpr_fnext;
 IO->xpr_finfo     = (long (*)())xpr_finfo;
 IO->xpr_fseek     = (long (*)())xpr_fseek;

 /* We do not support extension fields */
 IO->xpr_extension = 0;

 /* NULL out the XPR private data field. */
 IO->xpr_data      = NULL;

 return(TRUE);
}


LONG __stdargs __saveds __asm xpr_update(register __a0 struct XPR_UPDATE *x)

{char *msg = NULL;
 char  title[72];

 if (!quiet)
    {if (x->xpru_updatemask & XPRU_FILESIZE)    fsize = x->xpru_filesize / 1024;
     if (x->xpru_updatemask & XPRU_BYTES)       bytes = x->xpru_bytes    / 1024;
     if (x->xpru_updatemask & XPRU_BLOCKSIZE)   bsize = x->xpru_blocksize;
     if (x->xpru_updatemask & XPRU_DATARATE)    drate = x->xpru_datarate;

     if (x->xpru_updatemask & XPRU_FILENAME)
        {msg = FilePart(x->xpru_filename);
         strncpy(fname, msg, 15);
         fname[15] = 0;
        }

     if (x->xpru_updatemask & XPRU_ERRORMSG)
        {msg = x->xpru_errormsg;
         if (strlen(msg) > 50)  *(msg+50) = 0;
         ASPrintf(NULL, title, SA[3344], msg);
         TTitle(title, dsi->port);
         return(0);
        }

     if (x->xpru_updatemask & XPRU_MSG)
        {msg = x->xpru_msg;
         if (strlen(msg) > 50)  *(msg+50) = 0;
         ASPrintf(NULL, title, SA[3345], msg);
         TTitle(title, dsi->port);
         return(0);
        }
     ASPrintf(NULL, title, SA[3346], dsi->port, (tmode=='S')?SA[3347]:SA[3348], fname, fsize, bytes, bsize, drate);
     TTitle(title, dsi->port);
    }

 return(0);
}


/* xpr_gets is not supported, but we return 0 to satisfy certain protocols */
LONG __stdargs __saveds __asm xpr_gets(register __a0 char *prompt,register __a1 char *buffer)

{return(0);
}


/* xpr_setserial - reports/sets the serial parameters */
LONG __stdargs __saveds __asm xpr_setserial(register __d0 long nstatus)

{long         ostatus;
 long         cbaud;
 static ULONG baud[12] = {110, 300, 1200, 2400, 4800, 9600, 19200, 31250, 38400, 57600, 76800, 115200};

 dsi->read->IOSer.io_Command = SDCMD_QUERY;
 DoIO((struct IORequest *)dsi->read);

 ostatus = ((dsi->read->io_ExtFlags & 0x0000000F) << 8) + dsi->read->io_SerFlags;
 if (dsi->read->io_StopBits == 2)  ostatus |= 0x00000400;
 if (dsi->read->io_ReadLen  == 7)  ostatus |= 0x00000800;
 if (dsi->read->io_WriteLen == 7)  ostatus |= 0x00001000;

 for(cbaud = 0; cbaud < 12; cbaud++)
     if (RStruct.Baud_Rate <= baud[cbaud])
        {ostatus |= (cbaud << 16);
         break;
        }

 if (nstatus != -1)  return(-1);

 return(ostatus);
}


/**
*
*   Write a string to the serial port
*
**/
LONG __stdargs __saveds __asm xpr_swrite(register __a0 char *s,register __d0 long n)

{dsi->write->IOSer.io_Length =  n;
 dsi->write->IOSer.io_Data   = (APTR)s;

 DoIO((struct IORequest *)dsi->write);
 return(0);
}


/* Check for carrier */
BOOL CarrierDetect(void)

{UWORD cd;

 dsi->read->IOSer.io_Command = SDCMD_QUERY;
 DoIO((struct IORequest *)dsi->read);

 cd                          = dsi->read->io_Status;
 dsi->read->IOSer.io_Command = CMD_READ;

 return((BOOL)!(cd & 1<<5));
}


/**
*
*   Read characters from the serial port
*
**/
LONG __stdargs __saveds __asm xpr_sread(register __a0 UBYTE *buf,register __d0 long length, register __d1 long micros)

{long secs=0;

 if (buf == NULL) return(-1);

 if (!CarrierDetect())
    {abortflag = TRUE;
     return(-1);
    }

 if (!length)  return(0);

 if (micros)
    {/* If there is a timeout, use the timer */
     /* Set up the read */
     dsi->read->IOSer.io_Length  = length;
     dsi->read->IOSer.io_Data    = (APTR)buf;
     SendIO((struct IORequest *)dsi->read);

     if (micros>1000000)
        {/* Convert to secs and micros if necessary */
         secs   = micros/1000000;
         micros = micros%1000000;
        }

     Timer->tr_time.tv_secs  = secs;
     Timer->tr_time.tv_micro = micros;
     SendIO((struct IORequest *)Timer);

     for(;;)
        {Wait(READSER_SIG | TIMER_SIG);

        if (CheckIO((struct IORequest *)dsi->read))
           {WaitIO((struct IORequest *)dsi->read);

            AbortIO((struct IORequest *)Timer);
            WaitIO((struct IORequest *)Timer);
            SetSignal(0,TIMER_SIG);

            return((long)dsi->read->IOSer.io_Actual);
           }

        if (CheckIO((struct IORequest *)Timer))
           {AbortIO((struct IORequest *)dsi->read);
            WaitIO((struct IORequest *)dsi->read);
            SetSignal(0, READSER_SIG);

            return((long)dsi->read->IOSer.io_Actual);
           }
        }
    }
  else
    {/* Just see what's available right now */
     dsi->read->IOSer.io_Command = SDCMD_QUERY;
     DoIO((struct IORequest *)dsi->read);

     if (dsi->read->IOSer.io_Actual<length)
         length = dsi->read->IOSer.io_Actual;

     dsi->read->IOSer.io_Command = CMD_READ;

     if (length)
        {dsi->read->IOSer.io_Length  = length;
         dsi->read->IOSer.io_Data    = (APTR)buf;
         DoIO((struct IORequest *)dsi->read);
        }

     return(length);
    }
}


/**
*
*   Flush the serial buffer.
*
**/
LONG __stdargs __saveds xpr_sflush(void)

{dsi->read->IOSer.io_Command = CMD_CLEAR;
 DoIO((struct IORequest *)dsi->read);
  
 dsi->read->IOSer.io_Command = CMD_READ;
 return(0);
}


/**
*
*   Interfaces to stdio
*
**/
LONG __stdargs __saveds __asm xpr_fopen(register __a0 char *s,register __a1 char *t)

{filesopen++;

 if(tmode == 'R'  &&  Exists(s))   ResetComment(s);
 return((long)fopen(s, t));
}


LONG __stdargs __saveds __asm xpr_fclose(register __a0 FILE *fp)

{if (!filesopen) return(TRUE);

 filesopen--;
 return(fclose(fp));
}


LONG __stdargs __saveds __asm xpr_fread(register __a0 char *buff,register __d0 long size,register __d1 long count,register __a1 FILE *fp)

{return((LONG)fread(buff,size,count, fp));
}


LONG __stdargs __saveds __asm xpr_fwrite(register __a0 char *buff,register __d0 long size, register __d1 long count,register __a1 FILE *fp)

{return((LONG)fwrite(buff,size,count,fp));
}


LONG __stdargs __saveds __asm xpr_fseek(register __a0 FILE *fp,register __d0 long offset,register __d1 long origin)

{return(fseek(fp,offset,origin));
}


LONG __stdargs __saveds __asm xpr_ffirst(register __a0 char *buff,register __a1 char *pattern)

{BPTR   lock;
 char  *name;
 char  *rname;
 char   path[256];

 if (sc)
    {SearchEnd(sc);
     sc = NULL;
    }

 if (!batchmode)
    {if (!strchr(pattern, '?')  &&  !strchr(pattern, '*'))
        {strcpy(buff, pattern);
         return(TRUE);
        }

     name = FilePart(pattern);

     if (name != pattern)
        {strncpy(path, pattern, name - pattern);
         path[name - buff + 1] = 0;
         if (path[name - pattern] == '/')  path[name - pattern] = 0;
         sc   = SearchStart(path, name);
        }
      else
        {name = pattern;
         sc   = SearchStart(NULL, name);
        }

     rname = SearchNext(sc);
     if (rname)
        {strncpy(buff, pattern, name - pattern);
        *(buff + (name - pattern)) = 0;
         strcat(buff, rname);
         fsize = 0;
         bytes = 0;
         bsize = 0;
         drate = 0;
         return(TRUE);
        }
      else
        {SearchEnd(sc);
         sc = NULL;
         return(FALSE);
        }
    }

 if (GetFirstStruct(batchfile,(char *)&MyBatch,sizeof(MyBatch))==-1)  return(FALSE);

 strcpy(buff, MyBatch.path);
 strcat(buff, MyBatch.filename);

 if (MyBatch.free & TEMP_DOWNLOAD)
    {if (!Exists(tempdownloads))
        {if (!(lock = CreateDir(tempdownloads)))  return(FALSE);
         UnLock(lock);
        }

     ASPrintf(NULL, destfile, "%s/%s", tempdownloads, MyBatch.filename);
     if (Copy(buff, destfile))                    return(FALSE);
     strcpy(buff, destfile);
    }


 return(TRUE);
}


LONG __stdargs __saveds __asm xpr_fnext(register __d0 long oldstate,register __a0 char *buff,register __a1 char *pattern)

{char *name;

 if (batchmode)
    {name = FilePart(buff);
     DeleteStruct(batchfile, name, sizeof(struct Batch), 40);
     if (MyBatch.free & TEMP_DOWNLOAD)  DeleteFile(destfile);
     return(xpr_ffirst(buff, pattern));
    }

 if (sc)
    {name = FilePart(pattern);

     if (name != pattern)
        {strncpy(buff, pattern, name - pattern);
         buff[name - pattern + 1] = 0;
        }

     name = SearchNext(sc);
     if (name)
        {strcat(buff,    name);
         fsize = 0;
         bytes = 0;
         bsize = 0;
         drate = 0;
         return(TRUE);
        }

     SearchEnd(sc);
     sc = NULL;
    }

 return(FALSE);
}


/**
*
*   Check for Abort
*
**/
LONG __stdargs __saveds xpr_chkabort(void)

{if (abortflag || (SetSignal(0, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C))
     return(TRUE);
 return(FALSE);
}


/**
*
*   Check for miscellaneous items
*
**/
LONG __stdargs __saveds xpr_chkmisc(void)

{return(FALSE);
}


/**
*
*   File information
*
**/
LONG __stdargs __saveds __asm xpr_finfo(register __a0 char *filename,register __d0 long infotype)

{ULONG size;

 if (infotype == 1)
    {if (FileSize(filename, &size)==-1)
         return(FALSE);
       else
         return((long)size);
    }
  else
    if (infotype == 2)
        return(1); /* Just say it's a binary file */
}


void debug(char *str)

{Delay(100);
 TTitle(str, mydevice);
 Delay(100);
}
