#include <exec/types.h>
#include <exec/io.h>
#include <proto/exec.h>
#include <devices/serial.h>
#include <hardware/cia.h>
#include <devices/timer.h>
#include <libraries/dos.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <dos.h>

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

#include <proto/dlg.h>

#include <pragmas/dlg.h>

#include "zmodem.h"

int   Zmodem_Receive(char *);
int   Zmodem_Send(char *);
BOOL  OpenTimer(void);
void  CloseTimer(void);
void  CleanUp(char *);
void  Usage(char *);
void _CXBRK(void);

struct Library     *DLGBase = NULL;
struct LangStruct *ls       = NULL;
char             **SA       = NULL;

struct DLGSerInfo  *dsi     = NULL;
struct timerequest *Timer   = NULL;
struct MsgPort     *Timer_Port;

struct USER_DATA    UserDat;
struct Ram_File     RStruct;

UBYTE serin[20];
char  sbuff[133];
char  diskbuff[20480];

char  mydevice     [4];
char  tempdownloads[256];
char  destfile     [256];

int Online_NFiles;
int zresume=TRUE;

UBYTE  send      = TRUE;
UBYTE  quiet     = FALSE;
UBYTE  batchmode = FALSE;
UBYTE  hitmiss   = 70;

static char version[]="$VER: DLGZModem 2.0 © 1995-1998 by Digerati Dreams "__AMIGADATE__"";

void main(int argc, char **argv)

{char *filename = NULL;
 char *c;
 char  protocol = 'Z';

 DLGBase = OpenLibrary("dlg.library", 0);
 if (!DLGBase)  CleanUp("Unable to open DLG.library");

 while(--argc>0)
      {char *s;

       s = *++argv;

       if (*s++ == '-')
          {while(*s)
                {switch(*s++)
                       {case 's':
                        case 'S': send = TRUE;
                                  break;

                        case 'r':
                        case 'R': send = FALSE;
                                  break;

                        case 'b':
                        case 'B': batchmode = TRUE;
                                  break;

                        case 'q':
                        case 'Q': quiet = TRUE;
                                  break;

                        case 'h':
                        case 'H': if (!--argc) break;
                                  hitmiss = atoi(*++argv);
                                  break;

                        case 'p':
                        case 'P': if (!--argc) break;
                                  protocol = *(*++argv);
                                  break;

                        case 'f':
                        case 'F': if (!--argc) break;
                                  filename = *++argv;
                                  break;

                         default: Usage("Bad switch");
                                  break;
                       }
                }
          }
      }

 if (send && !filename)                         Usage("You must specify a file name");
 if (GetDevName(mydevice)==-1)                  CleanUp("Unable to get device name");
 if (!ReadUser(&RStruct,&UserDat,mydevice))     CleanUp("Unable to read user data");
 if (!OpenTimer())                              CleanUp("Unable to open timer");
 if ((dsi=DLGGetSer(mydevice,protocol))==NULL)  CleanUp("Unable to open serial.device");

 if (send)
     ASPrintf(NULL, tempdownloads, "FILE:TempDownloads/%s", RStruct.Name);
   else
    {if (!filename)
         ASPrintf(NULL, tempdownloads, "FILE:TempUploads/%s/",  RStruct.Name);
       else
         strcpy(tempdownloads, filename);
     filename = tempdownloads;

     for(c = filename + strlen(filename) - 1; c >= filename; c--)
        {if (*c == ' ')  continue;

         if (*c != ':'   &&  *c != '/')
            {*c++ = '/';
             *c   =  0;
            }

         break;
        }
    }
 UnderScore(tempdownloads);

 if (send)
    {if (!Zmodem_Send(filename))     CleanUp("Send Failed");
    }
  else
     if (!Zmodem_Receive(filename))  CleanUp("Receive Failed");

 CleanUp(NULL);
}


int Zmodem_Receive(char *flname)

{int c;

 c = proto(dsi->read,dsi->write,Timer,&diskbuff[0],20480L,dsi->read->io_Baud,flname,0,1);

 dsi->read->IOSer.io_Command = CMD_READ;
 dsi->read->IOSer.io_Length  =    1;
 dsi->read->IOSer.io_Data    = (APTR)&serin[0];
 SendIO((struct IORequest *)dsi->read);

 return(c);
}


int Zmodem_Send(char *flname)

{int   c;
 char *p;
 char *q;

  q = flname + strlen(flname);

  for(p = flname; p < q; p++)
     {if (*p==' ')
         {*p = '\0';
           continue;
         }

      if (!*p)  break;
     }

  c = proto(dsi->read,dsi->write,Timer,&diskbuff[0],20480L,dsi->read->io_Baud,flname,1,1);

  return(c);
}


void SendMsg(char *s)

{if (!quiet) DLGProtoStatus(dsi,NULL,NULL,s);
}


BOOL CheckCarrier()

{int status;

 if (check_abort())  return(FALSE);

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

 status = dsi->write->io_Status & CIAF_COMCD;
 dsi->write->IOSer.io_Command = CMD_WRITE;

 if (status)
     return(FALSE);
   else
     return(TRUE);
}


BOOL check_abort(void)

{if (SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
    {SendMsg("Received ^C...Aborting");
     return(TRUE);
    }

 return(FALSE);
}


BOOL OpenTimer(void)

{if (Timer_Port = CreatePort(NULL,NULL))
    {if ((Timer=(struct timerequest *)CreateExtIO(Timer_Port,sizeof(*Timer))))
        {if (!(OpenDevice(TIMERNAME, UNIT_MICROHZ,(struct IORequest *)Timer, 0)))
            {Timer->tr_node.io_Command = TR_ADDREQUEST;
             Timer->tr_node.io_Flags = NULL;
             Timer->tr_node.io_Error = NULL;

             return(TRUE);
            }
          else
             Timer->tr_node.io_Device = NULL;
        }
    }

 return(FALSE);
}


void CloseTimer(void)

{if (Timer)
    {if (Timer->tr_node.io_Device) CloseDevice((struct IORequest *)Timer);
     DeleteExtIO((struct IORequest *)Timer);
    }

 if (Timer_Port)  DeletePort(Timer_Port);
}


void CleanUp(char *s)

{if (dsi)
    {AbortIO((struct IORequest *)dsi->read);
     WaitIO ((struct IORequest *)dsi->read);
     SetSignal(0,dsi->read->IOSer.io_Message.mn_ReplyPort->mp_SigBit);
     DLGReleaseSer(dsi);
    }

 CloseTimer();

 if (send)     DelDir(tempdownloads, NULL);
 if (DLGBase)  CloseLibrary(DLGBase);
 if (s)        printf("\n Error: %s\n\n",s);

 exit(s?5:0);
}


void Usage(char *string)

{printf("\n %s\n\n",string);
 printf(" Usage:  DLGZmodem [-(s|r) -n -b -q -p <protocolchar>] -f <filename>\n\n");
 printf("   Description of Switches:\n\n");
 printf("   -s: Send file\n");
 printf("   -r: Receive file\n");
 printf("   -b: Batch mode\n");
 printf("   -q: Quiet mode - do not monitor transfer\n");
 printf("   -p: Designate the one-character label for this protocol\n");
 printf("   -f: Name of the file to send or recieve path\n\n");

 CleanUp(NULL);
}


void _CXBRK(void)

{CleanUp(NULL);
}
