#include "DLGAreaFix.h"

#include <link/io.h>

#define BUFSIZE 5000
#define HELPFILE "fido:DLGAreaFix.HLP"
#define BODYFILE "T:DLGSND.BODY"
#define MAX_ARGS 50

int               DoAreafix(char *, char *, char *, char *, char *);
int               WorkArea(char *, char *, char *);
int               FoundArea(struct area *, char *);
int               DeletefromArea(struct area *, char *);
int               AddtoArea(struct area *, char *);
struct   nodenum *ScanForToZone(struct nodenum *, int);
struct   nodenum *ScanForFromOrg(struct area *, char *);
struct   nodenum *ScanForToOrg(struct area *, char *);
struct   nodenum *insert_nodenum5(char *, short, short, short, short,
                                  char *, short, short, short, short, int);
int               ScanForPresence(struct area *, char *);
int               SendMsg(char *);
void              afprint_netnodes(struct nodenum *, BPTR);
void              CreateABNetNodes(struct nodenum *, BPTR, char *);
void              CreateReport(char *);
void              CreateZAreas(char *, char *, char *);
int               CheckAFRequest(char *, char *, char *, char *, char *, char *);
int               CopyHelpToReport(char *);
int               OpenAFXMessage(char *, char *, char *, BOOL);
int               ReportChanges(char *, char *);
int               SendReportMessage(char *, char *, char *);
int               ParseArgs(char **, char *);



int                 DO_Q, DO_L, DO_H, DO_U, DO_R, DO_I;

/* the following define is used for a buffer to copy the *
 * * areafix backup */

/// afprint_netnodes
void afprint_netnodes(struct nodenum *n, BPTR fh)
{
   int   eq = 0;

   char *stripstring[] = {"", "STRIP_SEEN-BY"};
   int  strip;

   for (; n;)
   {
      eq++;

      if (eq > 100)
         break;

      strip = n->strip;
   
      if (strip)
         strip = 1;

      AFPrintf(NULL,fh, "* Local: %s!%d:%d/%d.%d  Remote: %s!%d:%d/%d.%d %s\n",
              n->from_organization, n->from_zone, n->from_net, n->from_node,
              n->from_point, n->organization, n->zone, n->net, n->node, n->point, 
              stripstring[strip]);

      n = n->next_nodenum;

   }

   AFPrintf(NULL,fh, "*\n");
   return;
}
//-

/// CreateABNetNodes
void CreateABNetNodes(struct nodenum *n, BPTR fh, char *globaladdr)
{
   char *stripstring[] = {"NOSTRIP", "STRIP"};
   int   strip;
   BOOL  flag;
   char  work[100];
   char  UA[100];
   char  STP[25];

   int   count = 0;

   char  lastdomain[25];
   int   lastzone = 0;
   int   lastnet = 0;
   int   lastnode = 0;
   int   lastpoint = 0;

   strcpy(lastdomain, n->from_organization);
   lastzone = n->from_zone;

   strcpy(STP, "NOSTRIP");
   strcpy(UA, globaladdr);

   for (; n; n = n->next_nodenum)
   {
      count++;

      strip = n->strip;

      if (strip)
         strip = 1;

      ASPrintf(NULL, work, "%s", stripstring[strip]);

      if (Stricmp(STP, work))
      {
         strcpy(STP, work);
         AFPrintf(NULL, fh, "\nCONT   %s \nCONT   ", STP);
         count = 0;
      }

      ASPrintf(NULL, work, "%s!%d:%d/%d.%d",
               n->from_organization, n->from_zone, n->from_net,
               n->from_node, n->from_point);

      if (Stricmp(work, UA) && Stricmp(n->from_organization, "_UNKNOWN_"))
      {
         strcpy(UA, work);
         AFPrintf(NULL, fh, "\nCONT   USEADDRESS %s \nCONT   ", UA);
         count = 0;
      }

      flag = FALSE;

      if (Stricmp(lastdomain, n->organization))
      {
         strcpy(lastdomain, n->organization);
         AFPrintf(NULL, fh, "%s!", lastdomain);
         flag = TRUE;
      }

      if (lastzone != n->zone || flag)
      {
         lastzone = n->zone;
         AFPrintf(NULL, fh, "%d:", lastzone);
         flag = TRUE;
      }

      if (lastnet != n->net || flag)
      {
         lastnet = n->net;
         AFPrintf(NULL, fh, "%d/", lastnet);
         flag = TRUE;
      }

      if (lastnode != n->node || flag || n->point)
      {
         lastnode = n->node;
         AFPrintf(NULL, fh, "%d", lastnode);
         flag = TRUE;
      }

      if (n->point)
      {
         lastpoint = n->point;
         AFPrintf(NULL, fh, ".%d", lastpoint);
      }

      if (count == 6)
      {
         count = 0;
         AFPrintf(NULL, fh, "\nCONT  ");
      }

      AFPrintf(NULL, fh, " ");

   }

   AFPrintf(NULL, fh, "\n");
   return;
}
//-

/// CreateReport
void CreateReport(char *reportname)
{
   BPTR  fh;
   int   passthru;
   int   link;
   int   alias;

   char  anchoraddress[100];

   struct area   *ThisArea;

   char *passthrustring[] = {"NOPASSTHRU", "PASSTHRU"};
   char *linkstring[] = {"NOLINK", "LINK"};
   char *aliasstring[] = {"NOALIAS", "ALIAS"};

   ASPrintf(NULL, logstring, ".  Creating %s report", reportname);
   Log(logstring);

   ThisArea = a->first_area;

   if (ThisArea)
   {
      fh = Open(reportname, MODE_NEWFILE);

      if (fh != NULL)
      {
         AFPrintf(NULL, fh, "*****  List of Known Areas *****");

         for (; ThisArea; ThisArea = get_next_area(ThisArea))
         {
            passthru = ThisArea->passthru;
            link = ThisArea->link;
            alias = ThisArea->alias;

            ASPrintf(NULL, anchoraddress, "%s!%d:%d/%d.%d", ThisArea->from_organization, ThisArea->from_zone, ThisArea->from_net, ThisArea->from_node, ThisArea->from_point);

            if (passthru)
               passthru = 1;

            if (link)
               link = 1;

            if (alias)
               alias = 1;

            AFPrintf(NULL, fh, "\n*\n* Area %s Path %s Area Number %d Anchor %s \n* Class %d %s %s %s\n*\n",
                     ThisArea->name, ThisArea->path, ThisArea->areanum, 
                     anchoraddress, ThisArea->class, passthrustring[passthru], 
                     linkstring[link], aliasstring[alias]);

            if (ThisArea->description)
               AFPrintf(NULL, fh, "Description: %s\n", ThisArea->description);

            if (ThisArea->first_nodenum)
               afprint_netnodes(ThisArea->first_nodenum, fh);
         }

         Close(fh);
      }
   }
}
//-

/// CreateZAreas
// This is the function that rebuilds the .ARE file...
void CreateZAreas(char *reportname, char *shortbak, char *longbak)
{
   int   RELOCKIT = 0;
   BPTR  src;
   BPTR  targ;
   char *buf;
   BPTR  fh;
   int   passthru;
   int   link;
   int   alias;

   int   i;

   char  work[100];

   char *pretty[] =
         {
            ";*******************************************", 
            ";=============",
            ";---------"
         };

   char  GLOBALFROM[75];
   char  GLOBALLINK[25];
   char  GLOBALPASS[25];
   char  GLOBALALIAS[25];
   int   GLOBALCLASS = -1;

   struct area      *ThisArea;
   struct nodenum   *n;

   char *passthrustring[] = {"NOPASSTHRU", "PASSTHRU"};
   char *linkstring[] = {"NOLINK", "LINK"};
   char *aliasstring[] = {"NOALIAS", "ALIAS"};

   Log("-> Rebuilding DLGMail.ARE...");

   strcpy(GLOBALFROM, "");
   strcpy(GLOBALLINK, "");
   strcpy(GLOBALPASS, "");
   strcpy(GLOBALALIAS, "");

#ifdef NEWROSSAREAS

   if (_AREALOCK)
      RELOCKIT = 1;

   if (_AREALOCK)
      UnLock(_AREALOCK);

   _AREALOCK = 0;
   _AREACRC = 0;
#endif

   DeleteFile(shortbak);

   if (!SmartRename(reportname, shortbak))
   {
      Log(".  Old DLGMail.ARE file backed up");

      fh = Open(reportname, MODE_NEWFILE);

      if (fh != NULL)
      {
         Log(".  Opened DLGMail.ARE file");

         AFPrintf(NULL,fh, ";Areafix rebuild of DLGMail.ARE file\n\n");

         ThisArea = a->first_area;

         if (ThisArea)
         {
            for (; ThisArea; ThisArea = get_next_area(ThisArea))
            {
               n = ThisArea->first_nodenum;

               if (n)
               {
                  ASPrintf(NULL, work, "%s!%d:%d/%d.%d",
                           ThisArea->from_organization, ThisArea->from_zone, 
                           ThisArea->from_net, ThisArea->from_node, 
                           ThisArea->from_point);

                  if (Stricmp(work, GLOBALFROM))
                  {
                     strcpy(GLOBALFROM, work);

                     AFPrintf(NULL, fh, "\n%s\nMYADDRESS %-30s  ;*\n%s\n", pretty[0], 
                              GLOBALFROM, pretty[0]);
                  }
               }

               passthru = ThisArea->passthru;

               if (passthru)
                  passthru = 1;

               ASPrintf(NULL, work, "%s", passthrustring[passthru]);

               if (Stricmp(work, GLOBALPASS))
               {
                  strcpy(GLOBALPASS, work);

                  AFPrintf(NULL, fh, "\n%s\n%-10s  ;=\n%s\n", pretty[1], GLOBALPASS, pretty[1]);
               }

               link = ThisArea->link;

               if (link)
                  link = 1;

               ASPrintf(NULL, work, "%s", linkstring[link]);

               if (Stricmp(work, GLOBALLINK))
               {
                  strcpy(GLOBALLINK, work);
                  AFPrintf(NULL, fh, "\n%s\n%-6s  ;-\n%s\n", pretty[2], GLOBALLINK, pretty[2]);
               }

               alias = ThisArea->alias;

               if (alias)
                  alias = 1;

               ASPrintf(NULL, work, "%s", aliasstring[alias]);

               if (Stricmp(work, GLOBALALIAS))
               {
                  strcpy(GLOBALALIAS, work);
                  AFPrintf(NULL, fh, "\n%s\n", GLOBALALIAS);
               }

               if (ThisArea->class != GLOBALCLASS)
               {
                  GLOBALCLASS = ThisArea->class;
                  AFPrintf(NULL, fh, "\nCLASS %d\n", GLOBALCLASS);
               }

               AFPrintf(NULL, fh, "\nTAG    %-25s ", ThisArea->name);

               if (passthru)
               {
                  strsfn(ThisArea->path, NULL, work, NULL, NULL);
                  AFPrintf(NULL, fh, "%-25s ; PASS:%s/", work, work);
               }
               else
               {
                  AFPrintf(NULL, fh, "%d                     ; MSG:%d/", ThisArea->areanum, ThisArea->areanum);
               }

               if (ThisArea->description)
                  AFPrintf(NULL, fh, "\nCONT DESC %s", ThisArea->description);

               AFPrintf(NULL, fh, "\nCONT   ");

               CreateABNetNodes(n, fh, GLOBALFROM);
            }
         }

         Log(".  Closing new DLGMail.ARE file");
         Close(fh);

#ifdef NEWROSSAREAS

         if (RELOCKIT)
         {
            while (1)
            {
               _AREALOCK = Lock("FIDO:DLGMail.ARE", ACCESS_WRITE);

               if (!_AREALOCK)
               {
                  Log("!  Error locking DLGMail.ARE!");
               }
               else
                  break;

               Delay(25);
            }
         }
#endif

      }

/* append shortbak to longback if longback exists */

      targ = Lock(longbak, ACCESS_READ);

      if (targ)
      {
         Log(".  Appending backup to DLGAreas.LOG file");
         UnLock(targ);
         Spawn(Input(), sout, "c:Date >>%s", longbak);

         buf = (char *) AllocMem(BUFSIZE, MEMF_PUBLIC | MEMF_CLEAR);

         if (buf != NULL)
         {
            targ = Open(longbak, MODE_OLDFILE);

            if (targ)
            {
               Seek(targ, 0, OFFSET_END);

               src = Open(shortbak, MODE_OLDFILE);

               if (src != NULL)
               {
                  while (1)
                  {
                     i = Read(src, buf, BUFSIZE);
                     Write(targ, buf, i);

                     if (i != BUFSIZE)
                        break;
                  }
                  Close(src);
               }

               ASPrintf(NULL, work, "\n---\n\n");
               Write(targ, work, 6);
               Close(targ);
            }
            FreeMem(buf, BUFSIZE);
         }
      }
   }

   Log("<- Done rebuilding ARE file");
}
//-

/// ReplyReport
void ReplyReport(char *reportname, char *fiveDaddr, int type, char *classes)
{
   BPTR fh;

   struct area *Area;

   int   IsActive;
   BOOL  ClassOK;

   int   c1 = 0;
   int   c2 = 0;

   Log("-> Generating report for reply...");

   Area = a->first_area;

   fh = Open(reportname, MODE_READWRITE);
   
   if (fh != NULL)
   {
      Seek(fh,0,OFFSET_END);

      if (type == ACTIVE)
         AFPrintf(NULL,fh, "Address [%s] active for the following MESSAGE areas:\n\n", fiveDaddr);

      if (type == AVAILABLE)
         AFPrintf(NULL, fh, "The following MESSAGE areas are available to [%s]\n\n", fiveDaddr);

      AFPrintf(NULL,fh, "Key Tagname                    Description (if available)\n");
      AFPrintf(NULL,fh, "--- -------------------------  --------------------------------------\n");

      for (; Area; Area = get_next_area(Area))
      {
         IsActive = CheckActive(Area->first_nodenum, fiveDaddr);

         if (type == ACTIVE)
         {
            if (IsActive)
            {
               if (IsActive == 1)
                  AFPrintf(NULL, fh, "F   ");
               else
                  AFPrintf(NULL, fh, "A   ");

               AFPrintf(NULL,fh, "%-25s  ", Area->name);

               if (Area->description)
                  AFPrintf(NULL,fh, "%-46.46s", Area->description);

               AFPrintf(NULL,fh, "\n");
               c1++;
            }
         }

         if (type == AVAILABLE)
         {
            ClassOK = CheckClass(Area->class, classes);

            if (ClassOK || IsActive)
            {
               BOOL ttt = FALSE;

               if (IsActive == 1)
               {
                  if (ClassOK)
                     AFPrintf(NULL, fh, "F   ");
                  else
                     AFPrintf(NULL, fh, "UF  ");

                  ttt = TRUE;
               }

               if (IsActive > 1)
               {
                  if (ClassOK)
                     AFPrintf(NULL, fh, "A   ");
                  else
                     AFPrintf(NULL, fh, "UA  ");

                  ttt = TRUE;
               }

               if (IsActive == 0 && ClassOK)
               {
                  if (ClassOK)
                     AFPrintf(NULL, fh, "    ");

                  ttt = TRUE;
               }

               if (ttt)
               {
                  AFPrintf(NULL, fh, "%-25s  ", Area->name);

                  if (Area->description)
                     AFPrintf(NULL, fh, "%-46.46s", Area->description);
                     AFPrintf(NULL, fh, "\n");
               }
               
               if (IsActive)
                  c1++;
               
               if (ClassOK)
                  c2++;
               
               if (!ClassOK && IsActive)
                  c2++;
            }
         }
      }
      
      AFPrintf(NULL, fh, "\n");
      AFPrintf(NULL, fh, "Key: A=Active F=Feed U=Unauthorized\n\n");

      if (type == ACTIVE)
      {
         AFPrintf(NULL, fh, "Active in [%d] areas\n", c1);
      }
      
      if (type == AVAILABLE)
      {
         AFPrintf(NULL, fh, "Active in [%d] of [%d] available areas\n", c1, c2);
      }

      Close(fh);
   }
   else
      Log("!  Couldn't open reply message to append report to");

   Log("<- Report completed.");
}
//-

/// CheckAFRequest
CheckAFRequest(char *sysopname, char *password, char *address, char *classes,
               char *altaddress, char *tickflags)
{
   BPTR  fh;
   char  buffer[1000];

   char  sym[100];

   char *dummy;
   char *s;
   char *p;
   int   rc;

   int   sl;

   Log("-> Checking for node in DLGMail.AFX.");
   
   sl = sizeof(buffer);

   fh = Open("FIDO:DLGMail.AFX", MODE_OLDFILE);
   
   if (fh != NULL)
   {
      rc = 0;
   
      while (1)
      {
         s = FGets(fh,buffer, 9998);

         if (s == NULL)
         {
            Log("!  ERROR: No Entry for requesting address/operator");
            rc = AF_NO_ENTRY;
            break;
         }

         buffer[strlen(buffer) - 1] = NULL;  // dump the newline 
         p = buffer;

         if (*p == ';')
            continue;

         if (*p == NULL)
            continue;

     /* look for keyword SYSOP */

         p = mystpsym(p, sym, sl);

         if (Stricmp(sym, "SYSOP"))
         {
            continue;
         }
         
         p = mystpsym(p, sym, sl);
         
         if (Stricmp(sym, sysopname))
         {
            continue;
         }

     /* look for keyword ADDRESS */

         p = mystpsym(p, sym, sl);
         
         if (Stricmp(sym, "ADDRESS"))
         {
            Log("!  ERROR: Bad .AFX Syntax, expecting ADDRESS keyword");
            rc = AF_BAD_AFX_SYNTAX;
            break;
         }
         
         p = mystpsym(p, sym, sl);
         
         if (strlen(address) != stcpm(sym, address, &dummy))
         {
            continue;
         }
         
         strcpy(address, sym);

     /* look for keyword PASSWORD or USEADDRESS */

         p = mystpsym(p, sym, sl);

         strcpy(altaddress, "");

         if (!Stricmp(sym, "USEADDRESS"))
         {
            p = mystpsym(p, sym, sl);
            strcpy(altaddress, sym);
            Log(".  System Using Alternate DLGMail.ARE address");
            Log(altaddress);

            p = mystpsym(p, sym, sl);
         }

         if (Stricmp(sym, "PASSWORD"))
         {
            Log("!  ERROR: Bad .AFX Syntax, expecting PASSWORD keyword");
            rc = AF_BAD_AFX_SYNTAX;
            break;
         }
         
         p = mystpsym(p, sym, sl);
         
         if (Stricmp(sym, password))
         {
            Log("!  User password doesn't match configured password");
            rc = AF_BAD_PASSWORD;
            break;
         }

     /* look for keyword CLASSES */

         p = mystpsym(p, sym, sl);
         
         if (!(!Stricmp(sym, "CLASSES") || !Stricmp(sym, "MSGCLASSES")))
         {
            Log("!  ERROR: Bad .AFX Syntax, expecting CLASSES keyword");
            rc = AF_BAD_AFX_SYNTAX;
            break;
         }
         
         p = mystpsym(p, sym, sl);
         strcpy(classes, sym);

         if (!RAIDFLAG)
         {
            rc = AF_OK;
            break;
         }
         else
         {
            /* RAID */
            strcpy(classes, "");

           /* look for keyword FILECLASSES */

            p = mystpsym(p, sym, sl);
            
            if (Stricmp(sym, "FILECLASSES"))
            {
               Log("!  ERROR: Bad .AFX Syntax, expecting FILECLASSES keyword");
               rc = AF_BAD_AFX_SYNTAX;
               break;
            }
            
            p = mystpsym(p, sym, sl);
            strcpy(classes, sym);

           /* look for keyword TICKFLAGS */

            strcpy(tickflags, "");

            p = mystpsym(p, sym, sl);

            if (Stricmp(sym, "TICKFLAGS"))
            {
               Log("!  ERROR: Bad .AFX Syntax, expecting FILECLASSES keyword");
               rc = AF_BAD_AFX_SYNTAX;
               break;
            }
            
            p = mystpsym(p, sym, sl);
            strcpy(tickflags, sym);

            rc = AF_OK;
            break;

         }
      }
      
      if (rc == 0)
         rc = AF_UNKNOWN_ERR;

      Log("<- Completed checking");
      Close(fh);
      return (rc);
   }
   else
   {
      Log("<- Couldn't open FIDO:DLGMail.AFX file");
      return (AF_NO_AFX);
   }
}
//-

/// AreaFix
AreaFix(int msgnumber)
{
   char  reportname[] = "T:AREAFIX.MSG";
   char  classes[200];
   char  sysopname[50];
   char  password[50];
   char  commands[50];
   char  areas[1000];
   char  address[40];
   char  altaddress[40];
   char  tickflags[40];

   int   rc;

   Log("-> Main AreaFix loop");

   strcpy(classes, "");

/* fetch message, return strings for processing */

   if (!FetchMsg(msgnumber, sysopname, password, address, commands, areas, sizeof(areas)))
      return (0);

   areas[sizeof(areas) - 1] = 0; // make sure the thing is null-terminated 

   if (RAIDFLAG)
   {
      if (TS == NULL)
      {
         Log("!  Raid requested but no .TIC loaded...");
         AFPrintf(NULL, sout, "DLGMail.TIC file not loaded\n");
         return(0);
      }
   }

   strcpy(altaddress, "");

   rc = CheckAFRequest(sysopname, password, address, classes, altaddress, tickflags);

   if (*altaddress)
   {
      ASPrintf(NULL, logstring, ".  Using address [%s] to make changes", altaddress);
      Log(logstring);
      strcpy(address, altaddress);
   }

   if (OpenAFXMessage(reportname, sysopname, address, RAIDFLAG) < 1)
   {
      Log("!  ERROR: Couldn't initialize a return message");
      AFPrintf(NULL,sout,"ERROR: Couldn't initialize a return message\n");
      return (0);
   }

   if (rc < 1)
   {
      if (rc == AF_UNKNOWN_ERR)
         ReportChanges(reportname, "Unknown Areafix Error. Please try your request again later...");

      if (rc == AF_NO_AFX)
         ReportChanges(reportname, "No Areafix config file available, please notify areafix operator...");

      if (rc == AF_BAD_PASSWORD)
         ReportChanges(reportname, "You've specified an invalid Areafix password...");

      if (rc == AF_BAD_ADDRESS)
         ReportChanges(reportname, "Your Areafix address is invalid...");

      if (rc == AF_NO_ENTRY)
         ReportChanges(reportname, "No entry for your node in Areafix config file...");

      if (rc == AF_BAD_AFX_SYNTAX)
         ReportChanges(reportname, "Bad syntax detected in Areafix config file, please notify operator...");

      ReportChanges(reportname, "");
      ReportChanges(reportname, "Remainder of Areafix message ignored...\n");

      SendReportMessage(reportname, sysopname, address);
      return (-1);
   }

   if (!RAIDFLAG)
      CreateReport("LOGS:BEFORE_AFX.RPT");

   rc = DoAreafix(reportname, address, classes, areas, tickflags);

   if (!RAIDFLAG)
      CreateReport("LOGS:AFTER_AFX.RPT");

   if (rc > 1 && !RAIDFLAG)
   {
      Log(".  Writing new DLGMail.ARE file");
      CreateZAreas("FIDO:DLGMail.ARE", "FIDO:DLGMail.ARE.BAK", "LOGS:DLGMail.ARE.LOG");
   }

   if (rc)
      DO_Q = 1;

   if (1)
   {
      char *ss, *pp;
      char  comtok[100];

      Upper(commands);
      ss = commands;
      ss = stpblk(ss);

      if (*ss)
      {
         while (1)
         {
            if (*ss == NULL || ss == NULL)
               break;

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

            pp = comtok;
            pp++;

            switch (*pp)
            {
               case 'R':
                        DO_R = 1;
                        break;

               case 'Q':
                        DO_Q = 1;
                        break;

               case 'L':
                        DO_L = 1;
                        break;

               case 'U':
                        DO_U = 1;
                        break;

               case 'I':
                        DO_I = 1;
                        break;

               case 'H':
                        DO_H = 1;
                        break;
            }
         }
      }

      if (DO_R)
      {
         ReportChanges(reportname, "");
         ReportChanges(reportname, "");
         ReportChanges(reportname, "The %RESCAN (-R) command not yet supported by DLGAreaFix");
      }

      if (DO_Q)
      {
         Log("-Q command");
         ReportChanges(reportname, "");
         ReportChanges(reportname, "");
         if (!RAIDFLAG)
            ReplyReport(reportname, address, ACTIVE, classes);
         else
            RaidReplyReport(reportname, address, ACTIVE, classes);
      }

      if (DO_L)
      {
         Log("-L command");
         ReportChanges(reportname, "");
         ReportChanges(reportname, "");
         if (!RAIDFLAG)
            ReplyReport(reportname, address, AVAILABLE, classes);
         else
            RaidReplyReport(reportname, address, AVAILABLE, classes);
      }

      if (DO_U)
      {
         ReportChanges(reportname, "");
         ReportChanges(reportname, "");
         ReportChanges(reportname, "The %UNLINKED (-U) command not yet supported by DLGAreaFix");
      }

      if (DO_I)
      {
         ReportChanges(reportname, "");
         ReportChanges(reportname, "");
         ReportChanges(reportname, "The %INFO (-I) command not yet supported by DLGAreaFix");
      }

      if (DO_H)
      {
         ReportChanges(reportname, "");
         ReportChanges(reportname, "");
         CopyHelpToReport(reportname);
      }
   }

   SendReportMessage(reportname, sysopname, address);
   Log("<- Completed Areafix loop");
   return (1);
}
//-

/// CopyHelpToReport
CopyHelpToReport(char *reportname)
{
   BPTR  fh;
   BPTR  in;
   char  buffer[100];

   in = Open(HELPFILE, MODE_OLDFILE);
   
   if (in != NULL)
   {
      fh = Open(reportname, MODE_READWRITE);

      if (fh != NULL)
      {
         Seek(fh,0,OFFSET_END);

         while (FGets(in,buffer,sizeof(buffer)))
         {
            AFPrintf(NULL,fh, "%s", buffer);
         }
         Close(fh);
      }
      Close(in);
   }
   return(1);
}
//-

/// OpenAFXMessage
OpenAFXMessage(char *reportname, char *sysopname, char *address, BOOL raidflag)
{
   BPTR  fh;

   char  dummy[50];
   char *p;

   ASPrintf(NULL,logstring, ".  Opening a reply message to [%s], [%s]", address, sysopname);
   Log(logstring);

/* new way to find the address */

   p = strchr(address, '!');

   if (p)
   {
      p++;
      strcpy(dummy, p);
   }
   else
   {
      AFPrintf(NULL,sout,"strange, no ! in address [%s]\n", address);

      p = strchr(address, ':');

      if (p)
      {
         if (p == address)
         {
            ASPrintf(NULL,dummy, "%d%s", _MyZone, address);
         }
         else
         {
            strcpy(dummy, address);
         }
      }
      else
      {
         ASPrintf(NULL,dummy, "%d:%s", _MyZone, address);// fix for address 0:0/0.0
      }
   }

   DeleteFile(reportname);

   fh = Open(reportname, MODE_NEWFILE);
   
   if (fh != NULL)
   {
      AFPrintf(NULL,fh, "TO: %s\n", sysopname);

      if (!raidflag)
         AFPrintf(NULL,fh, "FROM: DLGAreaFix (Areafix)\n");
      else
         AFPrintf(NULL,fh, "FROM: DLGAreaFix (Raid)\n");

      AFPrintf(NULL,fh, "SUBJECT: Reply to Areafix request\n");
      AFPrintf(NULL,fh, "FIDOADDRESS: %s\n", dummy);
      AFPrintf(NULL,fh, "PRIVATE\n");
      AFPrintf(NULL,fh, "BODY:\n");
      AFPrintf(NULL,fh, "DLGAreaFix (C) 1995-1997 DLG Development\n\n");
      Close(fh);
      return (1);
   }
   return (0);
}
//-

/// ReportChanges
ReportChanges(char *filename, char *string)
{
   BPTR  fh;

   if (*string)
   {
      ASPrintf(NULL,logstring,".  %s",string);
      Log(logstring);

   }

   fh = Open(filename, MODE_READWRITE);

   if (fh != NULL)
   {
      Seek(fh,0,OFFSET_END);
      AFPrintf(NULL,fh, "%s\n", string);
      Close(fh);
   }

   return(1);
}
//-

/// SendReportMessage
SendReportMessage(char *filename, char *sysop, char *address)
{
   if (SendMsg(filename))
   {
      Log(".  DLGAreaFix reply message sent");
      AFPrintf(NULL,sout,"DLGAreaFix reply message sent\n");
   }
   else
   {
      Log("!  DLGAreaFix reply message failed");
      AFPrintf(NULL,sout,"DLGAreaFix reply message failed\n");
   }
   return (1);
}
//-

/// ParseArgs
ParseArgs(char **argv, char *argstring)
{
   char                token[100];
   char               *s;
   int                 i = 0;

   s = argstring;

   argv[i] = NULL;

   while (*s != NULL && i < MAX_ARGS)
   {
      s = stpblk(s);

      if (*s)
      {
         argv[i] = s;
         i++;
         argv[i] = NULL;
         s = stptok(s, token, sizeof(token), " \t");
         if (*s)
            *s++ = NULL;
      }
   }
   return (i);
}
//-

/// DoAreafix
DoAreafix(char *reportname, char *address, char *classes, char *areas,
          char *tickflags)
{

/* this funcion must return 2 or higher to indicate that
 * something meaningful happened...
 */

   BPTR  fh;

   int   ac;
   int   rc = 0;
   char *ap;
   char  workp[150];

   char *curar;

   char  curarea[25];
   char *curarea_snt;

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

   ap = areas;

   while (1)
   {
      if (*ap == '\n' || *ap == NULL)
         break;

      ap = stpblk(ap);
      ap = stptok(ap, curarea, sizeof(curarea) - 1, " \n");

      Upper(curarea);
      curar = curarea;
      curarea_snt = curarea;

      if (*curar && (*curar == '-' || *curar == '+'))
         curar++;

      if (*curarea_snt && *curarea_snt == '+')
         curarea_snt++;

      ASPrintf(NULL,logstring,".  Processing request for [%s]",curarea);
      Log(logstring);
      AFPrintf(NULL,sout,"Processing request for area [%s]: ", curar);

      if (RAIDFLAG)
         ac = RaidWorkArea(address, classes, curarea_snt, tickflags);
      else
         ac = WorkArea(address, classes, curarea_snt);

      if (ac == 15)
      {
         Log(".  Added");
         AFPrintf(NULL,sout,"Added...\n");
         ASPrintf(NULL,workp, "%25.25s  ...Area added", curar);
         ReportChanges(reportname, workp);
      }

      if (ac == -16)
      {
         Log(".  Removed");
         AFPrintf(NULL,sout,"Removed...\n");
         ASPrintf(NULL,workp, "%25.25s  ...Area removed", curar);
         ReportChanges(reportname, workp);
      }

      if (ac == 9)
      {
         Log(".  Already active");
         AFPrintf(NULL,sout,"Already active...\n");
         ASPrintf(NULL,workp, "%25.25s  ...Request ignored, already active", curar);
         ReportChanges(reportname, workp);
         ac = 0;
      }

      if (ac == 3 || ac == -3)
      {
         Log(".  Unauthorized to make changes");
         AFPrintf(NULL,sout,"Unauthorized...\n");
         ASPrintf(NULL,workp, "%25.25s  ...Request ignored, unauthorized to add/remove", curar);
         ReportChanges(reportname, workp);
         ac = 0;
      }

      if (ac == 5 || ac == -5 || ac == 6 || ac == -6)
      {
         Log(".  Parser problem on .AFX or short on memory");
         AFPrintf(NULL,sout,"Parser problem on .AFX OR short memory...\n");
         ASPrintf(NULL,workp, "%25.25s  ...Unknown error - try again later", curar);
         ReportChanges(reportname, workp);
         ac = 0;
      }

      if (ac == -7)
      {
         Log(".  Not active, not removed");
         AFPrintf(NULL,sout,"Not active, not removed...\n");
         ASPrintf(NULL,workp, "%25.25s  ...Request ignored, not active", curar);
         ReportChanges(reportname, workp);
         ac = 0;
      }

      if (ac == -99)
      {
         int   trc;

         Log("#  Unavailable area");

         if (!RAIDFLAG)
         {
            Log("-> Upstream request...");

            AFPrintf(NULL,sout,"Upstream Search...\n");
            trc = FindIt(address, classes, curar);

            Log("<- Done Upstream");

            if (trc < 1)
            {
               Log(".  Can't find area on any feed.");
               AFPrintf(NULL,sout,"Can't find area on any feed...\n");
               ASPrintf(NULL,workp, "%25.25s  ...Area unavailable on any feed", curar);
               ReportChanges(reportname, workp);

               fh = Open("fido:NoAFX.que", MODE_READWRITE);

               if (fh)
               {
                  Seek(fh,0,OFFSET_END);
                  Log(".  Added to unprocessible queue");
                  AFPrintf(NULL,fh, "%-25.25s\t%s\t!CLASSES! %s\n", address, curar, classes);
                  Close(fh);
               }
               ac = 0;
            }
            else
            {
               AFPrintf(NULL,sout,"Ah! Area found...\n");
               ASPrintf(NULL,workp, "%25.25s  ...Area added, request autoforwarded", curar);
               ReportChanges(reportname, workp);

               fh = Open("fido:UpstreamedAFX.que", MODE_OLDFILE);

               if (fh)
               {
                  Seek(fh,0,OFFSET_END);
                  Log(".  Added to upstream queue");
                  AFPrintf(NULL, fh, "%-25.25s\t%s\t!CLASSES! %s\n", address, curar, classes);
                  Close(fh);
               }
               ac = 15;
            }
         }
         else
         {
            AFPrintf(NULL,sout,"Unavailable area...\n");
            ASPrintf(NULL,workp, "%25.25s  ...Area unavailable, netmail operator", curar);
            ReportChanges(reportname, workp);

            fh = Open("fido:raid.que", MODE_READWRITE);

            if (fh)
            {
               Seek(fh,0,OFFSET_END);
               Log(".  Added to queue");
               AFPrintf(NULL,fh, "%-25.25s\t%s\t!CLASSES! %s\n", address, curar, classes);
               Close(fh);
            }
            ac = 0;
         }
      }

      if (ac)
         rc = 2;
   }

   if (RAIDFLAG)
   {
      int   rc2;

      Log(".  Saving DLGMail.TIC");
      rc2 = SaveDLGMAILTIC();

      if (rc2 == 0)
         rc = 0;
   }

   Log("<- DoAreaFix() returning");
   return (rc);
}
//-

/// WorkArea
WorkArea(char *address, char *classes, char *curarea)
{
   struct area        *ThisArea;
   int   rc = -99;
   int   sc = 0;
   char  tmp[30];
   BOOL  add = TRUE;

   if (*curarea == '-')
   {
      add = FALSE;
      strcpy(tmp, curarea + 1);
   }
   else
      strcpy(tmp, curarea);

   for (ThisArea = a->first_area; ThisArea; ThisArea = get_next_area(ThisArea))
   {
      if (!Stricmp(tmp, ThisArea->name))
      {
         if (_MyDEBUG)
            AFPrintf(NULL,sout,"\tfound the area\n");

         rc = FoundArea(ThisArea, classes);

         if (_MyDEBUG)
            AFPrintf(NULL,sout,"\tFoundArea() returned %d\n", rc);

         if (rc)
         {
            if (add)
            {
               sc = AddtoArea(ThisArea, address);
            }
            else
            {
               sc = DeletefromArea(ThisArea, address);
               sc *= -1;
            }
         }
         else
         {
            sc = 3;

            if (_MyDEBUG)
               AFPrintf(NULL,sout,"guy has no class\n");
         }
         break;
      }
   }

   if (sc)
      rc = sc;

   if (rc == -99)
   {
      ;

      if (_MyDEBUG)
         AFPrintf(NULL,sout,"area isn't in area.bbs list\n");
   }

   if (rc == -99 && add == FALSE)
      rc = -7;

   return (rc);
}
//-

/// FoundArea
FoundArea(struct area * TA, char *classes)
{
   char *ap;
   char  curclass[10];
   int   cc;

   ap = classes;

   while (1)
   {
      if (*ap == '\n' || *ap == NULL)
         break;

      ap = stpblk(ap);
      ap = stptok(ap, curclass, sizeof(curclass) - 1, " \n");
      cc = atoi(curclass);

      if (TA->class == cc)
         return (1);
   }

   return (0);
}
//-

/// DeletefromArea
DeletefromArea(struct area * ta, char *address)
{
   short zone, net, node, point;
   char  domain[100];
   struct nodenum     *n;
   struct nodenum    **last;
   int   code;

   if (_MyDEBUG)
      AFPrintf(NULL,sout,"\t\ttrying to delete from area\n");

   code = parse5dstring(address, domain, &zone, &net, &node, &point);

   if (code)
      return(5);   // Syntax error in address

   last = &ta->first_nodenum;

   for (n = ta->first_nodenum; n;)
   {
      if (node == n->node     &&
          net == n->net       &&
          zone == n->zone     &&
          point == n->point   &&
          !Stricmp(domain, n->organization))
      {
        /* we have a match */

         *last = n->next_nodenum;
         n->next_nodenum = 0;
#ifndef NEWROSSAREAS
         delete_all_nodenum(n);
#endif
         return(16);
      }
      last = &n->next_nodenum;
      n = n->next_nodenum;
   }
   return(7);   // error: Couldn't find address I was told to delete.
}
//-

/// AddtoArea
AddtoArea(struct area * ta, char *address)
{
   short zone, net, node, point;
   char  domain[100];

   int   f_strip;
   short f_zone, f_net, f_node, f_point;
   char  f_domain[100];

   struct nodenum     *n;
   struct nodenum    **last;
   struct nodenum     *nn;

   struct nodenum     *fm_org = NULL;
   struct nodenum     *to_org = NULL;
   int   presence = 0;

   int   code;

   if (_MyDEBUG)
      AFPrintf(NULL,sout,"\t\ttrying to add to area\n");

   code = parse5dstring(address, domain, &zone, &net, &node, &point);

   if (code)
      return(5); // Syntax error in address.

   if (_MyDEBUG)
      AFPrintf(NULL,sout,"syntax OK\n");

   last = &ta->first_nodenum;
   n = ta->first_nodenum;

   if (n)
   {
      presence = ScanForPresence(ta, address);

      if (presence)
      {
         return(9);
      }

      fm_org = ScanForFromOrg(ta, address);
      to_org = ScanForToOrg(ta, address);
   }

/* if fm_org == NULL then there is no current distribution
 * to that domain w/ proper address
 *
 * if to_org == NULL then there is no current distribution to that domain at
 * all
 *
 * if to_org but fm_org == NULL then use send mail with from address as wrong domain
 *
 * if fm_org but to_org == NULL then this is really weird
 *
 * if both are null then punt
 */

/* handle most difficult problem first - no distribution list at all */

   if (n == NULL)
   {
      /* insert at head of distribution list */

      nn = insert_nodenum5(domain, zone, net, node, point, "_UNKNOWN_", 0, 0, 0, 0, 0);

      if (!nn)
      {
         AFPrintf(NULL,sout,"No mem\n");
            return(6);
      }

      nn->next_nodenum = n;
      *last = nn;
      AFPrintf(NULL,sout,"INS_HEAD\n");
      return (15);
   }

/* there's currently no distribution into that domain from that domain */

   if (n && to_org == NULL && fm_org == NULL)
   {
      /* insert at tail of distribution list, assume from info from previous entry */

      for (; n;)
      {
         strcpy(f_domain, n->from_organization);
         f_zone = n->from_zone;
         f_net = n->from_net;
         f_node = n->from_node;
         f_point = n->from_point;
         f_strip = n->strip;

         last = &n->next_nodenum;
         n = n->next_nodenum;
      }

      nn = insert_nodenum5(domain, zone, net, node, point, f_domain, f_zone, f_net, f_node, f_point, f_strip);

      if (!nn)
      {
         AFPrintf(NULL,sout,"No mem\n");
         return(6);
      }

      nn->next_nodenum = n;
      *last = nn;
      AFPrintf(NULL,sout,"INS_TAIL\n");
      return (15);
   }

   /* ideal! we found both from and to */

   if (fm_org && to_org)
   {
      n = to_org;
      n = ScanForToZone(n, zone);

      strcpy(f_domain, n->from_organization);
      f_zone = n->from_zone;
      f_net = n->from_net;
      f_node = n->from_node;
      f_point = n->from_point;
      f_strip = n->strip;

      last = &n->next_nodenum;
      n = n->next_nodenum;

      nn = insert_nodenum5(domain, zone, net, node, point, f_domain, f_zone, f_net, f_node, f_point, f_strip);

      if (!nn)
      {
         AFPrintf(NULL,sout,"No mem\n");
         return(6);
      }

      nn->next_nodenum = n;
      *last = nn;
      AFPrintf(NULL,sout,"INS_MID1\n");

      return (15);
   }

   /* next best thing - found the to org only */

   if (to_org)
   {
      n = to_org;

      n = ScanForToZone(n, zone);

      strcpy(f_domain, n->from_organization);
      f_zone = n->from_zone;
      f_net = n->from_net;
      f_node = n->from_node;
      f_point = n->from_point;
      f_strip = n->strip;

      last = &n->next_nodenum;
      n = n->next_nodenum;

      nn = insert_nodenum5(domain, zone, net, node, point,
                           f_domain, f_zone, f_net, f_node, f_point, f_strip);

      if (!nn)
      {
         AFPrintf(NULL,sout,"No mem\n");
         return(6);
      }

      nn->next_nodenum = n;
      *last = nn;
      AFPrintf(NULL,sout,"INS_MID2\n");

      return (15);
   }

   /* found the from org */

   if (fm_org)
   {
      n = fm_org;

      n = ScanForToZone(n, zone);

      strcpy(f_domain, n->from_organization);
      f_zone = n->from_zone;
      f_net = n->from_net;
      f_node = n->from_node;
      f_point = n->from_point;
      f_strip = n->strip;

      last = &n->next_nodenum;
      n = n->next_nodenum;

      nn = insert_nodenum5(domain, zone, net, node, point, f_domain, f_zone, f_net, f_node, f_point, f_strip);

      if (!nn)
      {
         AFPrintf(NULL,sout,"No mem\n");
         return(6);
      }

      nn->next_nodenum = n;
      *last = nn;
      AFPrintf(NULL,sout,"INS_MID3\n");

      return (15);

   }

   Log("!! ERROR! ERROR! ERROR! ERROR! ERROR!");
   AFPrintf(NULL,sout," ERROR! ERROR! ERROR! ERROR! ERROR! ERROR! ERROR! ERROR! ERROR!\n");
   return (0);
}
//-

/// ScanForToZone
struct nodenum     *ScanForToZone(struct nodenum *n, int zone)
{
   struct nodenum     *old_n;
   char  domain[100];
   BOOL  ourzone = FALSE;

   old_n = n;
   strcpy(domain, n->organization);

   if (zone == n->zone)
      ourzone = TRUE;

   for (; n;)
   {
      /* if the to domain changes, get the hell out */

      if (Stricmp(domain, n->organization))
         return old_n;

      /* domain still the same */

      if (ourzone)   // scan to when zone changes
      {
         if (zone == n->zone)
            old_n = n;
         else
            return old_n;
      }
      else
      {
         if (zone == n->zone)
         {
            ourzone = TRUE;
            old_n = n;
         }
      }

      n = n->next_nodenum;
   }
   return old_n;
}
//-

/// ScanForFromOrg
struct nodenum     *ScanForFromOrg(struct area *ta, char *address)
{
   short zone, net, node, point;
   char  domain[100];
   struct nodenum     *n;

   parse5dstring(address, domain, &zone, &net, &node, &point);

   n = ta->first_nodenum;

   for (; n;)
   {
      if (0 == Stricmp(domain, n->from_organization))
         return(n);

      n = n->next_nodenum;
   }
   return (0);
}
//-

/// ScanForToOrg
struct nodenum     *ScanForToOrg(struct area *ta, char *address)
{
   short zone, net, node, point;
   char  domain[100];
   struct nodenum     *n;

   parse5dstring(address, domain, &zone, &net, &node, &point);

   n = ta->first_nodenum;

   for (; n;)
   {
      if (!Stricmp(domain, n->organization))
         return(n);

      n = n->next_nodenum;
   }
   return (0);
}
//-

/// insert_nodenum5
struct nodenum     *insert_nodenum5(char *org, short zone, short net,
                                    short node, short point, char *f_org,
                                    short f_zone, short f_net, short f_node,
                                    short f_point, int f_strip)
{
   struct nodenum     *n;

   n = new(sizeof(struct nodenum));

   if (n == 0)
      return(0);

   n->next_nodenum = 0;

   stccpy(n->organization, org, MAX_STR);
   n->zone = zone;
   n->net = net;
   n->node = node;
   n->point = point;

   stccpy(n->from_organization, f_org, MAX_STR);
   n->from_zone = f_zone;
   n->from_net = f_net;
   n->from_node = f_node;
   n->from_point = f_point;

   n->strip = (int) f_strip;

   return(n);
}
//-

/// ScanForPresence
ScanForPresence(struct area * ta, char *address)
{
   short zone, net, node, point;
   char  domain[100];
   BOOL  flag = FALSE;
   struct nodenum     *n;

   parse5dstring(address, domain, &zone, &net, &node, &point);

   n = ta->first_nodenum;

   for (; n;)
   {
      if (!Stricmp(domain, n->organization) && zone == n->zone &&
         net == n->net &&
         node == n->node &&
         point == n->point)
      {
         flag = TRUE;
         break;
      }

      n = n->next_nodenum;
   }

   if (flag)
      return(1);
   return(0);
}
//-

/// SendMsg
SendMsg(char *infile)
{
   BPTR  in;
   BPTR  out;
   int   rc = 0;
   char *s;
   char  buffer[600];
   char  token[50];
   char  from[50];
   char  address[50];
   char  subject[80];
   char  to[50];
   char  area[50];
   BOOL  inbody = FALSE;

   strcpy(from, "DLGAreaFix");
   strcpy(to, "All");
   strcpy(subject, "Reply to Areafix request(s)");
   *area = NULL;
   *address = NULL;

   if (in = Open(infile, MODE_OLDFILE))
   {
      if (out = Open(BODYFILE, MODE_NEWFILE))
      {
         while (FGets(in, buffer, sizeof(buffer)))
         {
            if (inbody)
            {
               AFPrintf(NULL, out, buffer);
               continue;
            }

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

            s[strlen(s) - 1] = NULL;

            if (!Stricmp(token, "FROM:"))
            {
               strcpy(from, s);
               continue;
            }

            if (!Stricmp(token, "TO:"))
            {
               strcpy(to, s);
               continue;
            }

            if (!Stricmp(token, "SUBJECT:"))
            {
               strcpy(subject, s);
               continue;
            }

            if (!Stricmp(token, "AREA:"))
            {
               strcpy(area, s);
               continue;
            }

            if (!Stricmp(token, "FIDOADDRESS:"))
            {
               strcpy(address, s);
               continue;
            }

            if (!Stricmp(token, "BODY:"))
            {
               inbody = TRUE;
               continue;
            }
         }

         Close(out);

         ASPrintf(NULL,buffer, "DLG:SendMsg -n -q -f \"%s\" -s \"%s\" -b \"%s\" -r \"", from, subject, BODYFILE);

         if (*address)
         {
            strcat(buffer, "NET ");
            strcat(buffer, address);
            strcat(buffer, " ");
         }
         else
         {
            if (*area)
            {
               strcat(buffer, "AREA ");
               strcat(buffer, area);
               strcat(buffer, " ");
            }
         }
         strcat(buffer, to);
         strcat(buffer, "\"");

         ASPrintf(NULL,logstring,".  SendMsg: [%s]",buffer);
         Log(logstring);

         if (TestPCAddress(address))
            rc = Spawn(Input(),sout,buffer);
         else
            Log(".  Message not sent - Message was to Planet Connect");

         DeleteFile(BODYFILE);

      }
      Close(in);
   }
   return(rc);
}
//-


