/*ProfiPacket - packet radio terminal program
  Copyright (C) 1999  Alexander Feigl

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

  Author:

  Alexander Feigl
  Burachstraße 51

  D-88250 Weingarten

  Mail : Alexander.Feigl@gmx.de
*/


#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "QSO.h"
#include "GUIProtos.h"
#include "global.h"
#include "User.h"

#ifdef AmigaOS
#include <exec/memory.h>
#include <clib/exec_protos.h>
#include <inline/exec.h>
extern void *SysBase;
#undef RawDoFmt
#endif /*AmigaOS*/

static const unsigned char PLine_Conn[]=" Connected to ";
static const unsigned char PLine_Reconn[]=" Reconnected to ";
static const unsigned char PLine_Failure[]=" Failure with ";
static const unsigned char PLine_Busy[]=" Busy from ";

static void QSO_UserizeQSO(int channel,int restore);


static int SpecialStringCompare(const unsigned char *s1,
                                const unsigned char *s2)
 {
  const unsigned char *p1,*p2;
  int caseswitch=-1;


  p1=s1;
  p2=s2;
    
  while ( *p2!='\0')
   {
    if (*p1=='\0') return(0);
    if (*p1==*p2) 
     {
      ++p1;
      ++p2;
      continue;
     }
    if ( (*p2<0x41) || (*p2>0x7a) ) return(0);
    if ( (*p2>0x5a) && (*p2<0x61) ) return(0);
    
    if ( *p1== (*p2&0xdf) )
     {
      if (caseswitch==1) return(0);
      caseswitch=0;
     }
     else
     {
      if (*p1== (*p2|0x20) )
       {
        if (caseswitch==0) return(0);
        caseswitch=1;        
       }
       else
       {
        return(0);
       }
     }
    ++p1;
    ++p2;    
   }
  return(1);
 }


static int ExtractFwdCall(const unsigned char *ss,
                          unsigned char *ds)
 {
  int clen,inssid;
  const unsigned char *sptr;
  unsigned char *dptr;

  sptr=ss;
  dptr=ds;
  clen=0;
  inssid=0;

  while ( (*sptr!='\0') && (*sptr!='\r') && (*sptr!=' ') )
   {
    if (*sptr==':')
     {
      clen=0;
      dptr=ds;
      inssid=0;
      ++sptr;
      continue;
     }
    if (inssid)
     {
      if (clen==2) return(0);
      if ( (*sptr>'9') || (*sptr<'0') ) return(0);
      ++clen;
      *(dptr++)=*(sptr++);
      continue;
     }
    if (*sptr=='-')
     {
      inssid=1;
      clen=0;
      *(dptr++)=*(sptr++);
      continue;
     }
    if (clen==6) return(0);
    ++clen;
    *(dptr++)=*(sptr++);
   }
  *dptr='\0';
  return(1);
 }

int QSO_TestForwardConnect(int channel,const unsigned char *string)
 {
  struct QSO *qso;
  const unsigned char *sptr;

  QSO_TestPasswordString(channel,string);
  
  if ( (channel<1) || (channel>MaxChannel)) return(0);
  qso=QSOs+(channel-1);

  sptr=string;
  
  while (*sptr!='\0')
   {
    unsigned char callbuffer[16];
    if ( (sptr[0]=='*') && (sptr[1]=='*') && (sptr[2]=='*') )
     {
      sptr+=3;
     }
     else
     {
      while (*sptr!='\0')
       {
        if ( (*sptr=='>') || (*sptr==':') || (*sptr=='}') )
         {
          ++sptr;
          if (*sptr==' ') break;
         }
        ++sptr;
       }
      if (*sptr=='\0') return(0);
     }
    if (SpecialStringCompare(sptr,PLine_Conn))
     {
      /* connected to is detected */
      int freedigi;
      sptr+=StringLength(PLine_Conn);
      if (!ExtractFwdCall(sptr,callbuffer)) return(0);
      if (CompareString(callbuffer,qso->Call)) return(1);
      for (freedigi=0;freedigi<8;++freedigi)
       {
        if (qso->Path[freedigi][0]=='\0') break;
       }
      if (freedigi==8)
       {
        int i;
        for (i=1;i<8;++i)
         {
          CopyString(qso->Path[i-1],qso->Path[i]);
         }
        freedigi=7;
       }
      CopyString(qso->Path[freedigi],qso->Call);
      CopyString(qso->Call,callbuffer);
      QSO_CompressionOff(channel);
      QSO_EncryptionOff(channel);
      if (qso->User!=NULL)
       {
        QSO_CloseUser(qso->User);
        qso->User=NULL;
       }
      QSO_UserizeQSO(channel,0);
      return(1);
     }  
    
    if (SpecialStringCompare(sptr,PLine_Reconn))
     {
      int i;
      /* reconnected to is detected */
      sptr+=StringLength(PLine_Reconn);
      if (!ExtractFwdCall(sptr,callbuffer)) return(0);
      for (i=7;i>=0;--i)
       {
        if (CompareString(qso->Path[i],callbuffer)) break;
       }
      if (i>=0)
       {
        qso->Path[i][0]='\0';
       }
      CopyString(qso->Call,callbuffer);
      QSO_CompressionOff(channel);
      QSO_EncryptionOff(channel);
      if (qso->User!=NULL)
       {
        QSO_CloseUser(qso->User);
        qso->User=NULL;
       }
      QSO_UserizeQSO(channel,0);
      return(2);
     }
     
    if (SpecialStringCompare(sptr,PLine_Failure))
     {
      /* link failure is detected */
      sptr+=StringLength(PLine_Failure);
      if (!ExtractFwdCall(sptr,callbuffer)) return(0);
      return(3);
     }
     
    if (SpecialStringCompare(sptr,PLine_Busy))
     {
      /* busy is detected */
      sptr+=StringLength(PLine_Busy);
      if (!ExtractFwdCall(sptr,callbuffer)) return(0);
      return(3);
     }
    ++sptr;
   }
  return(0); 
 }

static void QSO_ReuserizeQSO(int channel)
 {
  struct QSO *qso;
  struct User *user,*linkuser;
  
 
  if ( (channel<1) || (channel>MaxChannel) ) return;
  qso=QSOs+(channel-1);
  user=qso->User;
  if (user==NULL) return;
  
  CopyString(qso->Name,user->Name);
#ifdef AmigaOS
  MAIN_ConvertToAmiga(qso->Name);
#endif
  
  linkuser=(user->LinkUse)?user:QSO_OpenStandardUser();
  if (linkuser!=NULL)
   {
    unsigned char combuf[16];
    unsigned long v;
    combuf[0]='F';
    combuf[1]=' ';
    
    v=linkuser->CurFrack;
    RawDoFmt("%ld",&v,PutRawDoFmt,combuf+2);
    QSO_SendCommand(StringLength(combuf),channel,combuf);
    
    combuf[0]='N';
    v=linkuser->CurTries;
    RawDoFmt("%ld",&v,PutRawDoFmt,combuf+2);
    QSO_SendCommand(StringLength(combuf),channel,combuf);
    
    combuf[0]='O';
    v=linkuser->CurMaxFrame;
    RawDoFmt("%ld",&v,PutRawDoFmt,combuf+2);
    QSO_SendCommand(StringLength(combuf),channel,combuf);
    
    if ( ( (qso->ConnectTime.ds_Days!=0) ||
         (qso->ConnectTime.ds_Minute!=0) ||
         (qso->ConnectTime.ds_Tick!=0)) &&
         (
          (qso->ConnectTime.ds_Days!=user->LastLogin.ds_Days) ||
          (qso->ConnectTime.ds_Minute!=user->LastLogin.ds_Minute) ||
          (qso->ConnectTime.ds_Tick!=user->LastLogin.ds_Tick)
         ) )
     {
      qso->LastLogin=user->LastLogin;
      user->LastLogin=qso->ConnectTime;
      QSO_ChangeUser(user);    
     }
    
    qso->StationID=user->StationID;
         
           
   }
    
 }

static void QSO_UserizeQSO(int channel,int restore)
 {
  struct QSO *qso;
  struct User *user;
  
  if ( (channel<1) || (channel>MaxChannel) ) return;
  qso=QSOs+(channel-1);
  qso->Name[0]='\0';
  if (restore)
   {
    qso->ConnectTime.ds_Days=0;
    qso->ConnectTime.ds_Minute=0;
    qso->ConnectTime.ds_Tick=0;
   }  
   else
   {
    qso->ConnectTime=CurrentDateStamp;
   } 
  qso->ActivityTime=CurrentDateStamp;
  qso->CurrentDir[0]='\0';
  qso->SysopMode=0;
  qso->PrivateDir=0;


  user=QSO_OpenUser(qso->Call);
  qso->User=user;
  if (user!=NULL)
   {
    QSO_ReuserizeQSO(channel);   
   }  
  GUIMAIN_ResetStyles(qso);
  GUI_RefreshConnectHead();
  GUI_RefreshPacketHead();
 }

void QSO_DoConnect(int channel,int self,int fresh)
 {
  struct QSO *qso;
  int restore;
  
  if ( (channel<1) || (channel>MaxChannel) ) return;
  qso=QSOs+(channel-1);
  
  restore=QSO_HoldRestorePre(channel,self,fresh);
 
  /* checking for call lock */
  
  if (fresh)
   {
    if (QSO_CheckCall(qso->Call))
     {
      QSO_SendCommand(1,channel,"D");
      return; 
     }
   }  
  QSO_UserizeQSO(channel,restore);
 
  if ( (qso->User!=NULL) && (qso->User->Type==3) && (fresh) )
   {
    /* disconnect user */ 
    unsigned char macrofname[32];   
    const unsigned char *sptr;
    unsigned char *dptr;
    CopyString(macrofname,"NOTCON_");
    dptr=macrofname+7;
    sptr=qso->Call;
    while ( (*sptr!='\0') || (*sptr!='-'))
     {
      *(dptr++)=*(sptr++);
     }    
    if (QSO_TransmitMacroFile(macrofname,channel,1))
     {
      QSO_TransmitMacroFile("NOTCON_GLOBAL",channel,1);
     }    
    QSO_ForceTransmit(channel);    
    QSO_SendCommand(1,channel,"D");   
   }
  
  if (restore)
   {
    QSO_HoldRestorePost(channel);
 #ifdef AmigaOS
    qso->XPKLibrary=NULL;
    if (qso->XPKType[0]!=0xff)
     {
      if (!QSO_XPKOpenLibrary(qso))
       {
        QSO_EncryptionOff(channel);
       }
     }
 #endif /*AmigaOS*/
   } 
   
  if (qso->Server==NULL)
   {
    if (QSO_InitalizeChannel(channel,(qso->StartupMsg)?1:self,
                         NULL))
     {
      QSO_SendCommand(1,channel,"D");
     }                         
   }   
 }
