/********************************************************************
* GCW.c    Gnome's Call Waiting switcher - for UK use only
*
* Auto: sc >ERR:<file>.err link <path><file>
*
* Send code to modem to dial out & send code
*   to switch Call Waiting on or off  (British Telecom system only)
*
* Usage: GCW [ON] [-w<waitvalue>] [-d<devicename>] [-u<unitnumber>]
*  e.g.  GCW -w3 -dgvpser.device -u1
*
*  Defaults: OFF  waitvalue=2  devicename=serial.device unitnumber=0 
*
*  waitvalue is the delay between dialling and hanging up.
*
***********************************************************************/

#define VER "1.00"

#include   <proto/exec.h>   /* enables use of exec library */
#include   <proto/dos.h>    /* enables use of dos library */
#include   <stdio.h>
#include   <stdlib.h>
#include   <string.h>
#include   <devices/serial.h>
#include   <devices/timer.h>
#include   <time.h>

#define TIMEOUTVALUE    2 /* seconds, default value */

const char version[] = "\0$VER: GCW (any device) "VER" ("__DATE__") "__TIME__" by Gnome";

/*----functions----*/
void cleanExit(UBYTE *, LONG);
void cleanup(void);
BYTE OpenSerial(struct IOExtSer *, struct IOExtSer *);
ULONG Wait(ULONG);
VOID DeleteExtIO(struct IORequest *);
void stoptimer(void);
BYTE OpenSerial(struct IOExtSer *, struct IOExtSer *);

struct MsgPort   *readmp=NULL;
struct MsgPort   *writemp=NULL;
struct MsgPort   *timermp=NULL;
struct Message   *TimerMSG=NULL;
struct IOExtSer  *readio=NULL;
struct IOExtSer  *writeio=NULL;
struct timerequest *timerio=NULL;
struct Library   *TimerBase;

int  serdeviceopen=0;
char inbuff[40];
BOOL timeropen=FALSE, timerset=FALSE;

int timeout = TIMEOUTVALUE;
char devicename[30]="serial.device";
int unitnumber = 0;
char CWcode[10] = "ATDT#43#\r"; /* default code to switch CW off */
char oncode[10] = "ATDT*43#\r"; /* code to switch CW on */

int main(argc, argv)
int argc;
char *argv[];
{
  ULONG mask, signalset;
  ULONG Wait();
  ULONG error;
  int i;
  char buffer[40];

  if(argc>1)
  {
    if (*argv[1]=='?')
    {
      printf("\nGCW v%s by Gnome\n",VER);
      printf("Call Waiting switcher for British Telecom systems.\n");
      printf("Tells modem to dial out code for CW on or off,\n");
      printf("and waits long enough to receive ack message.\n");
      printf("Usage: GCW [ON] [-w<waitvalue>] [-d<devicename>] [-u<unitnumber>]\n");
      printf("  e.g.  GCW -w3 -dgvpser.device -u1\n");
      printf("  Defaults: OFF  waitvalue=2  devicename=serial.device unitnumber=0\n");
      printf(" waitvalue is the seconds delay between dialling and hanging up.\n");
      printf("Arguments in any sequence, and not case conscious.\n\n");
      return(0);
    }
    else
    {
      for (i=2;i<=argc;i++)
      {
        strcpy(buffer,argv[i-1]);
        if(strnicmp(buffer,"ON",2)==0)
          strcpy(CWcode,oncode);
        if(strnicmp(buffer,"-W",2)==0)
          timeout = atoi(&buffer[2]);
        if(strnicmp(buffer,"-D",2)==0)
          strncpy(devicename,&buffer[2],28);
        if(strnicmp(buffer,"-U",2)==0)
          unitnumber = atoi(&buffer[2]);
      }
    }
  }

  if (!(readmp=CreateMsgPort()))
    cleanExit("GCW: Can't create serial read port\n",20);

  if (!(readio=(struct IOExtSer *)
      CreateExtIO(readmp,sizeof(struct IOExtSer))))
    cleanExit("GCW: Can't create serial read IO\n",20);

  if (!(writemp=CreateMsgPort()))
    cleanExit("GCW: Can't create serial write port\n",20);

  if (!(writeio=(struct IOExtSer *)
      CreateExtIO(writemp,sizeof(struct IOExtSer))))
    cleanExit("GCW: Can't create serial write IO\n",20);

  readio->io_SerFlags=SERF_SHARED | SERF_XDISABLED;

  if (error=OpenSerial(readio, writeio))
    cleanExit("GCW: Can't open device\n",20);
  else serdeviceopen=1;

  if (!(timermp=CreatePort(0,0)))
    cleanExit("GCW: Can't create timer messageport\n",20);

  if (!(timerio=(struct timerequest *) CreateExtIO(timermp,sizeof(struct timerequest)))) 
    cleanExit("GCW: Can't create timer request\n",20);

  if (error=OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *) timerio,0L))
    cleanExit("GCW: Can't open timer.device\n",20);

  timeropen=TRUE;  /* used by cleanup() */
  TimerBase=(struct Library *)timerio->tr_node.io_Device;

  timerio->tr_node.io_Command=TR_ADDREQUEST;
  timerio->tr_time.tv_secs= timeout;
  timerio->tr_time.tv_micro= 0;
  SendIO((struct IORequest *)timerio);  /* timer started here. Found to be      */
  timerset=TRUE;                        /* unreliable if started after dialling */

/*----------------- end of setup ----------------------*/

  writeio->IOSer.io_Length=-1;

  writeio->IOSer.io_Data=(APTR) &CWcode;  /**** dial out ****/

  writeio->IOSer.io_Command=CMD_WRITE;
  if (DoIO((struct IORequest *) writeio))   /* send command to modem */
    cleanExit("GCW: Write request failed\n",20); /* DoIO waits for completion */    

  readio->IOSer.io_Command = CMD_READ;
  readio->IOSer.io_Length  = 1;
  readio->IOSer.io_Data    = (APTR) &inbuff[0];

  SendIO((struct IORequest *) readio);  /* read serial port */
                                              /* SendIO doesn't wait */

  mask=(1L << readmp->mp_SigBit) | (1L << timermp->mp_SigBit)
     | SIGBREAKF_CTRL_C;

/*- - - - - MAIN LOOP - - - - - - - - - - -*/
  while(1)
  {
    signalset=Wait(mask);   /* **** THE WAIT **** */

    if (signalset & (1L << readmp->mp_SigBit))
    {
      if ( CheckIO((struct IORequest *) readio))  /* any news from the port? (null=busy) */
      {
        WaitIO((struct IORequest *) readio);       /* remove message */
        SendIO((struct IORequest *) readio);
      }
    }

    if (SIGBREAKF_CTRL_C & signalset) break;

    if (signalset & (1L << timermp->mp_SigBit))
    {                                           /* timed out */
      TimerMSG=GetMsg(timermp);      /* Clear message port */
      if(TimerMSG==(struct Message *) timerio)
      {
        timerset=FALSE;
        break;
      }
    }    /* end of if timer  */
  }   /* end of main loop  */
/*- - - - - - - - - - - - - - - - - - - - -*/

  AbortIO((struct IORequest *) readio);       /* Abort request if pending  */      
  WaitIO((struct IORequest *) readio);

  stoptimer();

  cleanup();
  return(0);
}
/*============================================================*/

void cleanup()
{
  if(timerset)       stoptimer();
  if(timeropen)      CloseDevice((struct IORequest *) timerio);
  if(timerio)        DeleteExtIO((struct IORequest *) timerio);
  if(timermp)        DeletePort(timermp);
  if(serdeviceopen)  CloseDevice((struct IORequest *) readio);
  if(writeio)  DeleteExtIO((struct IORequest *) writeio);
  if(writemp)  DeleteMsgPort(writemp);
  if(readio)   DeleteExtIO((struct IORequest *) readio);
  if(readmp)   DeleteMsgPort(readmp);
}

void cleanExit(UBYTE *txt, LONG rtn)
{
  if (*txt) printf(txt);
  cleanup();
  exit(rtn);
}
/*=======================================================================*/

BYTE OpenSerial(readreq, writereq)
struct IOExtSer *readreq, *writereq;
{
  BYTE error;

  error= OpenDevice(&devicename[0],unitnumber,(struct IORequest *) readreq,0);
  CopyMem(readreq, writereq, sizeof(struct IOExtSer));
  return (error);
}

void stoptimer()
{
  AbortIO((struct IORequest *) timerio);           /* stop timer     */
  WaitIO((struct IORequest *) timerio);            /* remove message */
  timerset=FALSE;
}

