#include "DLGAreaFix.h"

#include <link/io.h>

#define CTRL_A 1

void              BorrowNetArea(void);
void              ReturnNetArea(void);
int               IsMsgToMe(int, int, int, int);
int               readinmsg(char *, char **, ULONG *);
int               mywriteoutmsg(char *, char *, int, BOOL);

BOOL                RAIDFLAG = FALSE;

char               *remember = NULL;
int                 rememberlength;

/* the functions in this module constitute the outter most
 * * loop of processing the netmail area */

struct Fido_Msg_Header *FMH;

/// FetchMsg
FetchMsg(int msgnumber, char *from, char *password, char *address,
         char *commands, char *areas, int areassize)
{

   char  theirzone[100];
   char  theirnet[100];
   char  theirnode[100];

   char *p;

   int   pta;

   int   rc = 0;

   int   destinationzone;
   int   destinationnet;
   int   destinationnode;
   int   destinationpoint;

   int   pointkludge = 0;
   int   fromnet;
   int   fromnode;

   int   d_zone;
   int   d_net;
   int   d_node;
   int   d_point;

   char  kludge[170];
   int   kludgelength;

   char  token[50];
   char  name[255];

   BOOL  INTLKLUDGE = FALSE;
   BOOL  POINTKLUDGE = FALSE;

   int   f_point;

   char  t_add[50];

   char *s;

   char *start;     /* from readinmsg */
   ULONG   length;

   int   okay;

   Log("-> Entering FetchMsg()");

   while (1)
   {
      pointkludge = 0;

      ASPrintf(NULL,name, "%s%d.MSG", _NETMAILDIRPATH, msgnumber);
      ASPrintf(NULL,logstring, ".  Opening [%s] addressed to Areafix", name);
      Log(logstring);

      if (_MyDEBUG)
         AFPrintf(NULL,sout,"\n[%13.13s] ", name);

      okay = readinmsg(name, &start, &length);

      if (!okay)
      {
         AFPrintf(NULL,sout,"...Message %d Missing\n", msgnumber);
         Log("!  Message Missing");
         rc = AF_MSGMISSING;
         break;
      }

      FMH = (void *) start;

      if (!(!Stricmp(FMH->To, "Areafix")    ||
            !Stricmp(FMH->To, "DLGAreafix") ||
            !Stricmp(FMH->To, "DLGAfPl")    ||
            !Stricmp(FMH->To, "Raid")       ||
            !Stricmp(FMH->To, "DLGRaid")))
      {
         Log(".  Message Not to \"Areafix\" or \"DLGAreafix\" or \"DLGAfPl\" or \"Raid\" or \"DLGRaid\"\n");
         break;
      }

      if (!Stricmp(FMH->To, "Raid")   ||
          !Stricmp(FMH->To, "DLGRaid"))
      {
         RAIDFLAG = TRUE;
         Log(".  Message addressed to Raid function");
         AFPrintf(NULL,sout,"Message addressed to Raid\n");
      }
      else
      {
         Log(".  Message is to Areafix function");
         AFPrintf(NULL,sout,"Message addressed to Areafix\n");
      }

      destinationzone = _MyZone;
      destinationnet = FMH->DestNet;
      destinationnode = FMH->DestNode;
      destinationpoint = 0;

      fromnet = FMH->OrigNet;
      fromnode = FMH->OrigNode;

      /* put code in here to check for point and international
       * kludges and use those addresses instead of that in the
       * header */

      kludgelength = length - sizeof(struct Fido_Msg_Header);

      if (kludgelength > 168)
         kludgelength = 168;

      if (kludgelength > 0)
      {
         kludgelength = stccpy(kludge, (char *) (start + sizeof(struct Fido_Msg_Header)), kludgelength);

         kludge[kludgelength] = NULL;
         p = kludge;

         strcpy(logstring, "Looking for kludges... ");

         while (1)
         {
            p = strchr(p, CTRL_A);

            if (p == NULL)
            {
               break;
            }

            p++;              // get over control A

            p = stptok(p, token, sizeof(token), " \r\n");

            if (!Stricmp(token, "INTL"))
            {
               INTLKLUDGE = TRUE;

               p = stpblk(++p);  // get past known whitespace

               p = stptok(p, token, sizeof(token), " \r\n");

                 /* get  * address  * out  * of  * kludge  */

               if (_MyDEBUG)
                  AFPrintf(NULL,sout,"[INTL] ");

               strcat(logstring, "[INTL] ");

               strsfn(token, theirzone, theirnet, theirnode, NULL);
               d_zone = atoi(theirzone);
               d_net = atoi(theirnet);
               d_node = atoi(theirnode);

               if (d_net == destinationnet && d_node == destinationnode)
               {
                  destinationzone = d_zone;
               }

               p = stpblk(p++);
               p = stptok(p, token, sizeof(token), " \r\n");
               strcpy(t_add, token);

               if (_MyDEBUG)
                  AFPrintf(NULL,sout,"INTL TEMP ADDR: [%s]\n", t_add);

                 /* use this as destination */
            }

            if (!Stricmp(token, "TOPT"))
            {
               p = stpblk(++p);

               p = stptok(p, token, sizeof(token), " \r\n");

               if (_MyDEBUG)
                  AFPrintf(NULL,sout,"[TOPT] ");

               strcat(logstring, "[TOPT] ");
               d_point = atoi(token);

               destinationpoint = d_point;
            }

            if (!Stricmp(token, "FMPT"))
            {
               POINTKLUDGE = TRUE;

               p = stpblk(++p);

               p = stptok(p, token, sizeof(token), " \r\n");

               if (_MyDEBUG)
                  AFPrintf(NULL,sout,"[FMPT] ");

               strcat(logstring, "[FMPT] ");
               f_point = atoi(token);

            }
         }

         Log(logstring);
      }
      else
      {
         if (kludgelength < 0)
         {
            AFPrintf(NULL,sout,"ERROR! Kludgelength < 0 ... Please report to Steve\n");
            Log("!  ERROR! Kludgelength < 0, notify Jeff!");
         }
         else
            Log("!  Message has no body text");
      }

      if (_MyDEBUG)
         AFPrintf(NULL,sout,"-> [%d:%d/%d.%d] ", destinationzone, destinationnet, destinationnode, destinationpoint);

      ASPrintf(NULL,logstring, ".  Destination: [%d:%d/%d.%d] ", destinationzone, destinationnet, destinationnode, destinationpoint);
      Log(logstring);

      /* now we need to decide if we need to process the msg */
      /* ok, it's local and has been sent so no */
      /* ok, it's not from here but has already been sent so no */

      pta = IsMsgToMe(destinationzone, destinationnet, destinationnode, destinationpoint);

      if (destinationpoint)
      {
         Log("!  Oops! Message is to a point...");
         rc = AF_TOAPOINT;
         break;
      }

      /* ok, it's addressed to me (my main address or an AKA) so no */

      Log(".  Message is properly addressed to me, will process...");

      strcpy(from, FMH->From);
      s = FMH->Title;
      s = stpblk(s);
      s = stptok(s, password, 16, " \t\n\r");
      s = stpblk(s++);
      strcpy(commands, s);

/*
 * Look for magic keyword RAID after the password. If there, we "switch modes"
 * and work on files instead...
 */

      if (1)
      {
         char  raidtok[20];
         char  remainder[60];
         char *ss;

         ss = commands;

         ss = stptok(ss, raidtok, sizeof(raidtok), " \t");
         ss = stpblk(ss);

         strcpy(remainder, ss);

         if (!Stricmp(raidtok, "RAID"))
         {
            RAIDFLAG = TRUE;
            strcpy(commands, remainder);
         }
      }

      if (INTLKLUDGE == FALSE)
      {
         if (POINTKLUDGE == FALSE)
            ASPrintf(NULL,address, ":%d/%d.", FMH->OrigNet, FMH->OrigNode);
         else
            ASPrintf(NULL,address, ":%d/%d.%d", FMH->OrigNet, FMH->OrigNode, f_point);
      }
      else
      {
         if (POINTKLUDGE == FALSE)
            strcpy(address, t_add);
         else
            ASPrintf(NULL,address, "%s.%d", t_add, f_point);
      }

      ASPrintf(NULL,logstring, ".  From [%s]", address);
      Log(logstring);

      strcpy(areas, "");
      s = (char *) (start + sizeof(struct Fido_Msg_Header));

      while (s < start + length && *s)
      {
         if (*s == CTRL_A)
         {
            if (_MyDEBUG)
               AFPrintf(NULL,sout,"skipping ^A kludge\n");

            while (*s != '\r' && *s != '\n' && *s != NULL)
            {
               s++;
            }
         }                         

         if (*s == '\r' || *s == '\n')
         {
            s++;
            continue;
         }

         s = stpblk(s);
         s = stptok(s, token, sizeof(token), " \r\n\t");

         if (!Stricmp(token, "---"))
            break;

         if (!Stricmp(token, "%HELP"))
         {
            DO_H = 1;
            continue;
         }

         if (!Stricmp(token, "%INFO"))
         {
            DO_I = 1;
            continue;
         }

         if (!Stricmp(token, "%QUERY"))
         {
            DO_Q = 1;
            continue;
         }

         if (!Stricmp(token, "%LIST"))
         {
            DO_L = 1;
            continue;
         }

         if (!Stricmp(token, "%UNLINKED"))
         {
            DO_U = 1;
            continue;
         }

         if (!Stricmp(token, "%RESCAN"))
         {
            DO_R = 1;
            continue;
         }

         strncat(areas, " ", areassize - strlen(areas) - 5);
         strncat(areas, token, areassize - strlen(areas) - 5);
      }

      ASPrintf(NULL,logstring, ".  Changing areas [%s]", areas);
      Log(logstring);

      ASPrintf(NULL,logstring, ".  Sent commands [%s]", commands);

      AFPrintf(NULL,sout,"    FROM: %s\n", from);
      AFPrintf(NULL,sout," ADDRESS: %s\n", address);
      AFPrintf(NULL,sout,"COMMANDS: %s\n", commands);
      AFPrintf(NULL,sout,"   AREAS: %s\n", areas);

      if (_MyDEBUG)
         AFPrintf(NULL,sout,"What we're returning is:\n%s\n%s\n%s\n%s\n%s\n\n", from, password, address, commands, areas);

      rc = AF_OK;

      FMH->Attribute |= SENT;

      Log(".  Rewriting message with SENT bit set");
      mywriteoutmsg(name, start, length, FALSE);

      break;
   }
   FreeMem(remember, rememberlength);
   Log("<- Returning");
   return (rc);
}
//-

/// BorrowNetArea
void BorrowNetArea()
{
   BorrowArea(_NETMAILDIR,"AreaFix","Scanning for AreaFix messages",0,QUICKLOCK);
}
//-

/// ReturnNetArea
void ReturnNetArea()
{
   FreeArea(_NETMAILDIR,"AreaFix",QUICKLOCK);
}
//-

/// IsMsgToMe
int   IsMsgToMe(int destinationzone, int destinationnet, int destinationnode, int destinationpoint)
{
   int   rc = 0;

   int   i;

   char  myzone[10];
   char  mynet[10];
   char  mynode[10];
   char  mypoint[10];

   int   mzone;
   int   mnet;
   int   mnode;
   int   mpoint;

   /* this code does not account for messages which need to be
    * routed to any points feeding off this system */

   for (i = 0; i < _totADDRESS; i++)
   {
      strsfn(_ADDRESS[i], myzone, mynet, mynode, mypoint);
      mzone = atoi(myzone);
      mnet = atoi(mynet);
      mnode = atoi(mynode);
      mpoint = atoi(mypoint);

      if (mzone == destinationzone  &&
          mnet == destinationnet    &&
          mnode == destinationnode)
      {
         if (_MyDEBUG)
            AFPrintf(NULL,sout,"This msg matches my address %s\n", _ADDRESS[i]);

        /* put point matching code in right here */

         if (_MyDEBUG)
            AFPrintf(NULL,sout,"Test 1 is TRUE");

         rc |= 1;

         if (mpoint != destinationpoint)
         {
            if (_MyDEBUG)
               AFPrintf(NULL,sout,"Test 2 is true\n");

            rc |= 2;
         }
      }

      if (rc)
         return (rc);

   }

   return (0);
}
//-

/// readinmsg
readinmsg(char *name, char **start, ULONG *length)
{
   BPTR  fh;

   Log("-> Reading in message");

   fh = Open(name, MODE_OLDFILE);
   
   if (!fh)
   {
      Log("!  Can't open message");
      if (_MyDEBUG)
         AFPrintf(NULL,sout,"Message missing\n");
      return (0);
   }

   FileSize(name,length);  //2.63.1.1
   
   rememberlength = *length + 500;

   remember = (char *) AllocMem(rememberlength, MEMF_PUBLIC | MEMF_CLEAR);

   if (remember == NULL)
   {
      Log("!  Can't allocate memory for message");
      AFPrintf(NULL,sout,"ERROR: Couldn't allocate memory for message\n");
      Close(fh);
      return (0);
   }

   *start = remember;

   Read(fh, (void *) *start, *length);
   Close(fh);
   Log("<- Message read in");
   return (1);
}
//-

/// mywriteoutmsg
mywriteoutmsg(char *name, char *start, int length, BOOL kill)
{
   BPTR  fh;

   Log("-> Rewriting message");

   BorrowNetArea();

   if (kill)
   {
      Log(".  Message killed");
      DeleteFile(name);
      AFPrintf(NULL,sout,"Killed %s\n", name);
      ReturnNetArea();
      return (1);
   }

   fh = Open(name, MODE_NEWFILE);

   if (!fh)
   {
      Log("!  ERROR: Can't open file to rewrite message");
      AFPrintf(NULL,sout,"ERROR: Can't open output file!\n");
      ReturnNetArea();
      return (0);
   }

   Write(fh, (void *) start, length);
   Close(fh);
   ReturnNetArea();
   Log("<- Message rewritten");
   return (1);
}
//-
