//->$.Fax.!Arcfax.Driver.Class20V
// Copyright (c) David Pilling 1994
//



string modemhangup="ATH0";

int    modemdtespeed=57600;

int    modemusedocumentresolution=0;



string modeminitstring1="ATE1";
string modeminitstring2="ATQ0V1&C1S0=0S10=50";
string modeminitstring3="";




/****************************************************************************/


// The first section of the modem driver, contains general low level
// modem functions


int modemrxrate;
int modemtxrate;
int modembits;
int modemstop;
int modemparity;
int modemport;
int modemanswer;
int modemtonedial;
int modemflow;
int modemrings;
int modemmode;
int modemanswermode;




// count or purge buffer

int modem_countpurge(int rxtx,int code)
{
 return(devcon(Device_CountPurge,modemport,rxtx,code));
}


// tell modem to use a given sort of flow control

void modem_setflow(int flow)
{
 devcon(Device_Flow,modemport,flow,1);
 modemflow=flow;
}


// set rx rate

void modem_setrxrate(int rate)
{
 devcon(Device_RxRate,modemport,rate,1);
 modemrxrate=devcon(Device_RxRate,modemport,0,0);
}


// set tx rate

void modem_settxrate(int rate)
{
 devcon(Device_TxRate,modemport,rate,1);
 modemtxrate=devcon(Device_TxRate,modemport,0,0);
}


// set number of data bits

void modem_setbits(int bits)
{
 devcon(Device_DataBits,modemport,bits,1);

 modembits=devcon(Device_DataBits,modemport,0,0);
 modemparity=devcon(Device_ParityBits,modemport,0,0);
 modemstop=devcon(Device_StopBits,modemport,0,0);
}


// set parity bits

void modem_setparity(int parity)
{
 devcon(Device_ParityBits,modemport,parity,1);

 modembits=devcon(Device_DataBits,modemport,0,0);
 modemparity=devcon(Device_ParityBits,modemport,0,0);
 modemstop=devcon(Device_StopBits,modemport,0,0);
}


// set stop bits

void modem_setstop(int stop)
{
 devcon(Device_StopBits,modemport,stop,1);

 modembits=devcon(Device_DataBits,modemport,0,0);
 modemparity=devcon(Device_ParityBits,modemport,0,0);
 modemstop=devcon(Device_StopBits,modemport,0,0);
}


// set to tone/pulse dial

int modem_tonedial(int tonedial)
{
 modemtonedial=tonedial;
 return(modemtonedial);
}


void modem_setanswer(int answer)
{
 modemanswer=answer;
}


void modem_setmode(int mode)
{
 modemmode=mode;
}

   
int modem_cap(string & s)
{
 s="compression,ADPCM,0,0,GSM,1,1;";
 return(VOICE|FAX|DATA);
}



// is the modem on line ?

int modem_online(void)
{
 return(devcon(Device_Status,modemport,0,-1) & SERIAL_DCD);
}





int modemechoedcommand(string & s,int ok)
{
 int    n;
 string t;
 //        return(0);


 if(slen(s)==0) return(0);

 for(n=0;n<5;n++)
 {
  sprints(s);
  sprints("|M");
  while(1)
  {
   if(!sreadtext(t,100,100)) break;
   sgetc(10);

   if(s==t)
   {
    if(ok)
    {
     while(1)
     {
      if(!sreadtext(t,100,100)) break;
      sgetc(10);
      if(t=="OK") return(0);
     }
    }
    else return(0);
    break;
   }
  }
 }
 return(1);
}


// put modem off line

void modem_disconnect(void)
{
 devicedtr(1,modemport);
 pause(200);
 devicedtr(0,modemport);

 sprints("+++");
 pause(200);
 modemechoedcommand(modemhangup,1);
}


/*****************************************************************************/
// This section is concerned with Fax handling

int faxmodemretries;
int faxmodemresolution;
int faxmodemmaxbitrate;
int faxmodemminbitrate;
int faxmodemlength;
int faxmodemwidth;
int faxmodemdatacompression;
int faxmodemerrorcorrection;
int faxmodembinaryftp;
int faxcurrentresolution;


string faxmodemid;




// return parameter or -1 if error 

int fxgetparam(string & s)
{
 int n;
 int c;
 int i;

 i=0;

 while(1)
 {
  c=schar(s,i++);

  if(c>='0' && c<='9') break;
  else
  if(c==0) return(-1);
 }

 n=c-'0';

 while(1)
 {
  c=schar(s,i);

  if(c>='0' && c<='9') n=n*10+c-'0';
  else                 break;

  i++;
 }

 s=s<<i;

 return(n);
}


void faxdisconnect(void)
{
 modemechoedcommand("AT+FKS",1);
}


/****************************************************************************/
// Fax transmit logic

// Parameters for session

int txptr;
int txresln;             // resolution
int txbitrate;           // bit rate code
int txpagewidth;         // page width code
int txpagelength;        // page height code
int txdatacompression;   // data compression
int txerrorcorrection;   // error correction
int txbinaryftp;         // binary ftp
int txscantime;          // min scan time

// Parameters for document

int txdocpages;
int txdocresolution;
int txdocwidth;


// Transmit page transfer status

void faxtxFPTS(string & s)
{
 txptr=fxgetparam(s);
}

int txgooddocument;

void faxtxFHNG(string & s)
{
 int n;
 string temp;

 n=s/"+FHS";
 if(n) s=s<<n;
 temp=s;

 txgooddocument=fxgetparam(s);
 if(txgooddocument) logreason(temp);
}


// current session capabilities

void faxtxFDCS(string & s)
{
 txresln=fxgetparam(s);
 txbitrate=fxgetparam(s);
 txpagewidth=fxgetparam(s);
 txpagelength=fxgetparam(s);
 txdatacompression=fxgetparam(s);
 txerrorcorrection=fxgetparam(s);
 txbinaryftp=fxgetparam(s);
 txscantime=fxgetparam(s);
 faxtxscan(txbitrate,txscantime);
 faxtxparams(txpagelength,txdatacompression,txerrorcorrection,txbinaryftp);
}


// remote station capabilities

void faxtxFDIS(string & s)
{
 faxtxFDCS(s);
}


// called station ID
// return 1 if OK, else 0

int faxtxFCSI(string & s)
{
 int code;
 s=s<<6;
 faxtxid(s);
 code=txidok(s);

 if(!code) 
 {
  faxdisconnect();
  logreason("Bad ID");
 }

 return(code);
}


// get an xon character

int faxtxgetxon(void)
{
 int c;

 while(1)
 {
  c=sgetc(100);
  if(c==-1) return(1);
  else
  if(c==('Q'-64)) return(0);
 }
}



int faxtxspeedcheck(void)
{
 if(txbitrate<faxmodemminbitrate)
 {
  logreason("Too slow");
  return(1);
 }
 else
 {
  return(0);
 }
}


// called by main program, to set parameters for next doc to send

void faxmodem_txparams(int pages,int resolution,int width)
{
 txdocpages=pages;
 txdocresolution=resolution;
 txdocwidth=width;
}


// called by main program to transmit documents
// return 0 if transmission completed correctly

int faxmodem_txdocument(int txdocuments)
{
 int    doc;
 int    docok;
 int    page;
 int    hangup;
 int    pgerror;
 int    retrain;
 int    speedfail;
 string result;
 string s;

 docok=1;
 hangup=0;
 retrain=0;
 pgerror=0;
 speedfail=0;
 txgooddocument=1;

 for(doc=0;doc<txdocuments && !hangup;doc++)
 {
  faxtxopendocument();

  for(page=0;page<txdocpages && !hangup;page++)
  {
   retrain=0;
   if(modemechoedcommand("AT+FDT",0)) break;

   while(1)
   {
    if(!sreadtext(s,6000,100)) break;

    if(s/"+FCS"==0)
    {
     faxtxFDCS(s);
     speedfail=faxtxspeedcheck();
    }
    else
    if(s/"+FIS"==0)
    {
     faxtxFDIS(s);
     speedfail=faxtxspeedcheck();
    }
    else
    if(s/"CONNECT"==0) break;
    else
    if(s/"+FHS">=0)
    {
     hangup=1;
     faxtxFHNG(s);
     if(!txgooddocument) txgooddocument=1; //can get FHNG 0 without sending fax
     break;
    }
   }

   if(s/"CONNECT"!=0) break;
   
   faxtxgetxon();

   if(speedfail)
   {
    sputc(0x10);sputc(0x3);
    sreadtext(s,6000,100);
    faxdisconnect();
    pgerror=1;
   }
   else
   {
    modem_setflow(XONXOFF);

    pgerror=faxtxpage(page,txpagewidth,txresln);
                            // at this point can be a buffer of stuff   *

    sputc(0x10);

    if(page<(txdocpages-1))  sputc(0x2C);
    else                    
    {
     if(doc<(txdocuments-1)) sputc(0x3B);
     else                    sputc(0x2E);
    }

    if(pgerror) 
    {
     modem_setflow(RTSCTS);
     break;
    }
   }


   while(1)
   {
    if(!sreadtext(s,6000,100)) break;
    modem_setflow(RTSCTS);   // so we wait till now to switch off X flow *

    if(s/"+FPS"==0)
    {
     faxtxFPTS(s);
    }
    else
    if(s/"+FHS">=0)
    {
     faxtxFHNG(s);
     hangup=1;
     break;
    }
    else
    if(s=="OK")
    {
     txptr=0;
     break;
    }
    else
    if(s=="ERROR")
    {
     txptr=2;
     break;
    }
   }

   switch(txptr)
   {
    case 2:           /* bad page */
    case 3:
            retrain=1;
            break;
    default:
            break;
   }
  }

  faxtxclosedocument(!(page>=txdocpages)||(hangup && txgooddocument)||pgerror);
  if(page<txdocpages) break;
 }

 if(retrain && !hangup)
 {
  modemechoedcommand("AT+FDT",0);

  while(1)
  {
   if(!sreadtext(s,6000,100)) break;

   if(s/"CONNECT"==0)
   {
    faxtxgetxon();
    sputc(0x10);sputc(0x3);
   }
   else
   if(s/"+FHS">=0)
   {
    hangup=1;
    faxtxFHNG(s);
    break;
   }
  }
 }

 return(txgooddocument);
}


int faxmodemsetparams(void)
{
 string s;
 s="AT+FCC=";
 s=s+itos(faxcurrentresolution);
 s=s+",";
 s=s+itos(faxmodemmaxbitrate);
 s=s+",";
 s=s+itos(faxmodemwidth);
 s=s+",";
 s=s+itos(faxmodemlength);
 s=s+",";
 s=s+itos(faxmodemdatacompression);
 s=s+",0,0,0";
 return(modemechoedcommand(s,1));
}

// called by main program to set up parameters

void faxmodem_params(int res,int rate,int length,int width)
{
 faxmodemresolution=res;
 faxmodemmaxbitrate=rate;
 faxmodemlength=length;
 faxmodemwidth=width;
}

void faxmodem_params2(int data,int error,int binary,int rate)
{
 faxmodemdatacompression=data;
 faxmodemerrorcorrection=error;
 faxmodembinaryftp=binary;
 faxmodemminbitrate=rate;
}


int faxmodemsetid(void)
{
 string s;
 s="AT+FLI="+"\""+faxmodemid+"\"";
 return(modemechoedcommand(s,1));
}


// program the fax modem identifier

void faxmodem_id(string & id)
{
 faxmodemid=id;
}


// return 0 OK, 1 Error

int faxtxconnect(void)
{
 string s;

 while(1)
 {
  if(sreadtext(s,3000,200))
  {
   if(s/"+FCO"==0) continue;
   else
   if(s/"+FCI"==0) 
   {
    if(!faxtxFCSI(s)) return(1);
   }
   else
   if(s/"+FCS"==0) faxtxFDCS(s);
   else
   if(s/"+FIS"==0) faxtxFDIS(s);
   else
   if(s/"+FNF"==0) continue;
   else
   if(s=="OK") break;
  }
  else break;
 }

 return(s!="OK");
}


// set number of page retries

int faxmodem_retries(int retries)
{
 faxmodemretries=retries;
 return(faxmodemretries);
}


/****************************************************************************/
// Fax receive logic
//
//

int rxgooddocument;      // return code from FHNG
int rxresln;             // resolution 0==low 1==high
int rxbitrate;           // bit rate code
int rxpagewidth;         // page width code
int rxpagelength;        // page height code
int rxdatacompression;   // data compression
int rxerrorcorrection;   // error correction
int rxbinaryftp;         // binary ftp
int rxscantime;          // min scan time


int rxppm;               // rx post page message code
int rxptr;               // rx page transfer status


void faxrxFPTS(string & s)
{
 rxptr=fxgetparam(s);
 rxpagelength=fxgetparam(s);
}


void faxrxFDCS(string & s)
{
 rxresln=fxgetparam(s);
 rxbitrate=fxgetparam(s);
 rxpagewidth=fxgetparam(s);
 rxpagelength=fxgetparam(s);
 rxdatacompression=fxgetparam(s);
 rxerrorcorrection=fxgetparam(s);
 rxbinaryftp=fxgetparam(s);
 rxscantime=fxgetparam(s);
 faxrxscan(rxbitrate,rxscantime);
 faxrxparams(rxpagelength,rxdatacompression,rxerrorcorrection,rxbinaryftp);

}


void faxrxFET(string & s)
{
 rxppm=fxgetparam(s);
}


void faxrxFHNG(string & s)
{
 int n;
 string temp;

 n=s/"+FHS";
 if(n) s=s<<n;
 temp=s;

 rxgooddocument=fxgetparam(s);
 if(rxgooddocument) logreason(temp);
}


int faxrxFTSI(string & s)
{
 int code;
 s=s<<6;
 faxrxid(s);
 code=rxidok(s);

 if(!code) 
 {
  faxdisconnect();
  logreason("Bad ID");
 }

 return(code);
}


// called if get a +FCON after connect
// return 0 if good connect

int faxrxconnect(void)
{
 string s;

 while(1)
 {
  if(!sreadtext(s,3000,100)) break;

  if(s/"+FCO"==0) continue;
  else
  if(s/"+FCS"==0) faxrxFDCS(s);
  else
  if(s/"+FTI"==0) 
  {
   if(!faxrxFTSI(s)) return(1);   /* failed on id code */
  }
  else
  if(s/"+FHS">=0)
  {
   faxrxFHNG(s);
   break;
  }
  else break;
 }
 return(s!="OK");
}


// return 0 OK, 1 Error

int faxmodem_rxdocument(void)
{
 string s;
 string result;
 int    docok;
 int    newdocument;
 int    badpage; 
 int    page;

 newdocument=1;
 rxgooddocument=1;

 while(1)
 {
  modemechoedcommand("AT+FDR",0);

  while(1)
  {
   if(!sreadtext(s,6000,100)) break;

   if(s/"+FHS">=0) 
   {
    faxrxFHNG(s);
    break;
   }
   else
   if(s/"+FCS"==0) faxrxFDCS(s);
   else
   if(s/"CONNECT"==0) break;
  }

  if(s/"CONNECT"!=0) break;

  if(newdocument)
  {
   newdocument=0;
   page=0;
   faxrxopendocument();
  }

  sprints("|R");
  badpage=faxrxpage(page,rxpagewidth,rxresln);

  while(1)
  {
   if(!sreadtext(s,3000,100)) break;

   if(s/"+FPS"==0)  faxrxFPTS(s);
   else
   if(s/"+FET"==0)  faxrxFET(s);
   else
   if(s/"+FHS">=0)
   {
    faxrxFHNG(s);
    break;
   }
   else
   if(s=="OK") break;
  }

  if(s!="OK") break;

  switch(rxppm)
  {
   case 0:
          page++;
          break;

   case 1:
          if(!newdocument) faxrxclosedocument(0);
          newdocument=1;
          break;

   case 2:
          if(!newdocument) faxrxclosedocument(0);
          newdocument=1;
          break;
  }
 }
 if(!newdocument) faxrxclosedocument(1);

 modem_disconnect();

 return(rxgooddocument);
}


/****************************************************************************/
// return 0 if OK, 1 on fail

int faxconnect(void)
{
 if(modemanswer) return(faxrxconnect());
 else            return(faxtxconnect());
}

// return 0 if OK, 1 on fail

int faxsetup(void)
{
 int code;

 code=1;

 settxbor(1);
 setrxbor(1);

 if(!modemechoedcommand("AT+FBO=0",1))
 {
  if(!modemechoedcommand("AT+FCR=1",1))
  {
   if(!modemechoedcommand("AT+FNR=1,1,1,1",1))
   {
    if(!faxmodemsetparams())
    {
     code=faxmodemsetid();
    }
   }
  }
 }

 return(code);
}







int modemconnectstrings(void)
{
 string s;

 while(sreadtext(s,6000,100))
 {
  if(s=="+FCO")       return(faxconnect()?0:FAX);
  else
  if(s/"FAX"==0)      return(faxconnect()?0:FAX);
  else
  if(s/"CONNECT"==0)  return(DATA);
  else
  if(s/"VCON"==0)     return(VOICE);
  else
  if(s=="CED")        continue;
  else
  if(s/"PROTOCOL"==0) continue;
  else
  if(s/"RINGING"==0)  continue;
  else
  if(s/"CARRIER"==0)  continue;
  else
  if(s/"+FDM"==0)     continue;
  else
  if(slen(s)>1) 
  {
   logreason(s);
   break;
  }
 }

 return(0);
}


int modemconnectstring(void)
{
 int code;
 int dle;

 maskdle(1);
 code=modemconnectstrings();

 if(code==VOICE)
 {
  while(1)
  {
   dle=getdlet(100);
   if(dle=='c') 
   {
    code=FAX;
    modemechoedcommand("AT#CLS=2.0",1);
    modemechoedcommand(modemanswer?"ATA":"ATD",0);
    code=modemconnectstrings();
    break;
   }
   else
   if(dle=='a')
   {
    code=DATA;
    modemechoedcommand("AT#CLS=0",1);
    modemechoedcommand(modemanswer?"ATA":"ATD",0);
    code=modemconnectstrings();
    break;
   }
   else
   if(dle=='d')
   {
    code=VOICE;
    break;
   }
   else
   if(dle==-1)  break;
  }
 }

 maskdle(0);

 return(code);
}












/****************************************************************************/

int datamodem_getfiles(void)
{
 int code;

 code=ftpgetfiles();

 modem_disconnect();

 return(code);
}


int datamodem_sendfiles(int files)
{
 int code;

 code=ftpsendfiles();

 modem_disconnect();

 return(code);
}


/*****************************************************************************/
// voice modem functions

int    voicecompression;
int    voicebps;
int    voicesps;
int    voicesilence;
int    voicemaxmessage;
int    voicedevice;
int    voiceansweringcall;
string voiceanswerbuffer;







int xvoicemodem_device(int dev)
{
 int    xdev;
 string command;
 int    i;

 if(dev==MODEMLS)            xdev=2;
 else
 if(dev==PHONE)              xdev=1;
 else
 if(dev==MIC)                xdev=3;
 else
 if((dev==LINE) || (dev==0)) xdev=0;
 else                        xdev=1;
    

 for(i=0;i<5;i++)
 {
  command="AT#VLS="+itos(xdev);
  modemechoedcommand(command,0);
  sreadtext(command,600,100);    // expect VCON
  if(!xdev || command=="VCON") break;
 }

 return(0);
}





void voicesetup(void)
{
 string command;

 if(voicesilence) modemechoedcommand("AT#VSD=1",1);
 else             modemechoedcommand("AT#VSD=0",1);

 command="AT#VSP="+itos(voicesilence*10);
 modemechoedcommand(command,1);

 xvoicemodem_device(voicedevice);

 if(voicecompression)
 {
  modemechoedcommand("AT#VSM=128,8000",1);
 }
 else
 {
  modemechoedcommand("AT#VSM=129,8000",1);
  command="AT#VBS="+itos(voicebps);
  modemechoedcommand(command,1);
 }
}




int modemsetup(void)
{
 int    code;
 string s;


                modemechoedcommand(modeminitstring1,1);
           code=modemechoedcommand(modeminitstring2,1);
 if(!code) code=modemechoedcommand(modeminitstring3,1);


 if(modemmode==DATA) code=modemechoedcommand("AT+FCLASS=0",1);
 else
 if(modemmode==FAX || modemmode==(FAX|DATA))
                     code=modemechoedcommand("AT+FCLASS=2.0",1);
 else                code=modemechoedcommand("AT#CLS=8",1);


 if(!code)
 {
  if(modemmode & VOICE) voicesetup();
 }


 if(!code)
 {
  if(modemmode==FAX || modemmode==(FAX|DATA)) code=faxsetup();
 }

 if(!code)
 {
  if(modemmode)
  {
   if(modemmode!=DATA && modemmode!=FAX && (!(modemmode & VOICE)))
                      code=modemechoedcommand("AT+FAA=1",1);
   else
   if(modemmode==FAX) code=modemechoedcommand("AT+FAA=0",1);
  }
 }

 return(code);
}









void voicemodem_params(int compression,int bps,int sps)
{
 voicecompression=compression;
 voicebps=bps;
 voicesps=sps;
}


void voicemodem_params2(int silence,int maxmessage)
{
 voicemaxmessage=maxmessage;
 voicesilence=silence;
}



int voicemodem_device(int dev)
{
 voicedevice=dev;
 if(!dev) xvoicemodem_device(dev);
 return(0);
}



int voicemodem_play(int start)
{
 string command;
 int    code;

 if(start)
 {
  if(!voiceansweringcall)
  {
   maskdle(1);
   modemechoedcommand("AT#CLS=8",1);
   voicesetup();
  }

  modemechoedcommand("AT#VTX",0);
  sreadtext(command,600,100);     // expect connect 
 }
 else
 {
  sputc(0x10);
  sputc(0x3);

  while(1)
  {
   code=sreadtext(command,1200,100);
   if(!code) break;

   if(command/"VCON">=0) break;

   code=getdle();
   if(code!=0x10 && code!=0x3 && code!=-1 && voiceansweringcall) 
                                           voiceanswerbuffer+=chars(code);
  }


  if(!voiceansweringcall)
  {
   maskdle(0);
   modemsetup();
  }
 }

 return(0);
}









int voicemodem_record(int start)
{
 string command;
 int    code;

 if(start)
 {
  if(!voiceansweringcall)
  {
   modemechoedcommand("AT#CLS=8",1);
   voicesetup();
  }

  modemechoedcommand("AT#VRX",0);

  sreadtext(command,200,100);   // expect CONNECT
  sgetc(50);                    // swallow trailing LF

 }
 else
 {
  sputc(0x10);
  sputc(0x3);

  while(1)
  {
   code=sreadtext(command,150,100);
   if(!code) break;
   if(command/"VCON">=0) break;
  }

  sreadtext(command,200,100);           // expect VCON

  if(!voiceansweringcall) modemsetup();
 }

 return(0);
}




int gofaxmode(void)
{
 int code;

 modemechoedcommand("AT#CLS=2.0",1);
 faxsetup();
 modemechoedcommand(modemanswer?"ATA":"ATD",0);
 code=modemconnectstrings();

 if(code==FAX)   return(faxmodem_rxdocument());
 else
 if(code==DATA)  return(datamodem_getfiles());

 return(0);
}





/* default is to do a simple answering machine */

int voicemodem_answer(void)
{
 string command;
 int    dle;
 int    n;
 int    len;

 voiceansweringcall=1;
 voiceanswerbuffer="";
 maskdle(1);

// voicemodem_device(LINE);

 /* play !Message  */

 replaymessage("!Message");

 dle=-1;
 len=slen(voiceanswerbuffer);
 for(n=0;n<len;n++)
 {
  dle=schar(voiceanswerbuffer,n);
  if(dle=='c' || dle=='a' || dle=='d') break;
 }

 if(n>=len)
 {
  while(1)
  {
   dle=getdlet(200);
   if(dle=='c' || dle=='a' || dle=='d' || dle==-1) break;
  }
 }

 voiceansweringcall=0;
 maskdle(0);

 if(dle=='c' || dle=='a') return(gofaxmode());

 /* go beep        */

// modemechoedcommand("AT#VLS=2",0,5,500);
// pause(100);
// sreadtext(command,100,100);            // expect VCON
 modemechoedcommand("AT#VTS=[933,0,10]",0);
 sreadtext(command,300,100);            // expect OK

 /* record message */

 voiceansweringcall=1;

 recordmessage(voicemaxmessage);
 
 voiceansweringcall=0;

// voicemodem_device(0);

 modem_disconnect();

 return(0);
}




/***************************************************************************/
// High level general modem control functions
// return 0 on fail or connection type




// called when we want modem driver to sort out the incoming call
// return 0 on success


int modem_receive(int mode)
{
 int code;

 if(mode & FAX)   code=faxmodem_rxdocument();
 else
 if(mode & VOICE) code=voicemodem_answer();
 else
 if(mode & DATA)  code=datamodem_getfiles();
 else             code=0;

 modemechoedcommand("AT#CLS=0",1);

 modemsetup();

 return(code);
}







int modem_send(int mode,int files)
{
 if(mode & FAX)  return(faxmodem_txdocument(files));
 else
 if(mode & DATA) return(datamodem_sendfiles(files));

 return(1);
}




int modem_dial(string number)
{
 string s;
 int    code;

 if(modemusedocumentresolution==0) faxcurrentresolution=faxmodemresolution;
 else                              faxcurrentresolution=txdocresolution;

 code=modemsetup();
 if(!code)
 {
  if(modemanswer)   s="ATDR";
  else              s="ATD";

  if(modemtonedial) s=s+"T";
  else              s=s+"P";

  if(!modemechoedcommand(s+number,0))
  {
   code=modemconnectstring();

  }
 }
 return(code);
}


// return 0 on fail, or connection type

int modem_connect(void)
{
 string s;
 int    code;

 if(modemanswer || modemusedocumentresolution==0) faxcurrentresolution=faxmodemresolution;
 else                                             faxcurrentresolution=txdocresolution;

 code=modemsetup();
 if(!code)
 {
  if(!modemechoedcommand(modemanswer?"ATA":"ATD",0))
  {
   code=modemconnectstring();
  }
 }
 return(code);
}




// enter auto answer mode 
// return 0 on success

int modem_autoanswer(int rings,int mode)
{
 int    code;
 string s;

 code=1;
 modemrings=rings;
 modemanswermode=mode;
 setpoll(0);

 if(rings)
 {
  faxcurrentresolution=faxmodemresolution;
  code=modemsetup();
 }
 else
 {
  code=modemechoedcommand("AT+FCLASS=0",1);
 }

 setpoll(1);
 return(code);
}


// repeatedly called
// examine serial port for sign of incoming fax
// if returns call type then modem_connect is called
// return 0, carry on polling

int modem_poll(void)
{
 string s;
 int    rings;


// if(bbc_inkey(-1)) return(FAX|DATA|VOICE);

 if(sreadtext(s,50,100))
 {
  if(s=="RING")
  {
   rings=modemrings-1;

   while(1)
   {
    if(rings<=0) return(FAX|DATA|VOICE);

    if(!sreadtext(s,1000,100)) break;
    else
    if(s=="RING") rings--;
   }
  }
 }
 return(0);
}

/*****************************************************************************/

// cancel modem operation


void modem_interrupt(void)
{
 string s;
 sprints("|M");
 while(sreadtext(s,50,100));
}


int modem_voicedial(string & number)
{
 string s;
 modemechoedcommand((modemtonedial?"ATDT":"ATDP")+number+";",0);

 while(1)
 {
  if(!sreadtext(s,5000,100)) break;
  if(s=="OK") break;
 }
 modemechoedcommand(modemhangup,1);
 return(0);
}



// called when ArcFax is about to terminate
// good time to hang up line etc.

void modem_terminate(void)
{
 devcon(Device_Select,modemport,0,0);
}



int modem_initiate(int port)
{
 int  code;

 modemport=port;

 if(!devcon(Device_Claim,modemport,0,0)) return(2);

 devcon(Device_Select,modemport,1,0);

 devcon(Device_Channel,modemport,0,0);

 modem_setrxrate(modemdtespeed);
 modem_settxrate(modemdtespeed);

 modem_setbits(8);
 modem_setparity(0);
 modem_setstop(1);

 modem_setflow(RTSCTS);

 setdlemode(0x4|0x2);    /* 4==don't end pages with DLE ETX  */
                         /* 2==do DLE SUB -> DLE DLE mapping */

 setpoll(0);

 // Some modems may like a short pause at this point

 pause(150);

                modemechoedcommand(modeminitstring1,1);
           code=modemechoedcommand(modeminitstring2,1);
 if(!code) code=modemechoedcommand(modeminitstring3,1);

 setpoll(1);

 if(code) devcon(Device_Select,modemport,0,0);

 return(code);
}


void main(void)
{


}

