/* raid functions go in here */

#include "DLGAreaFix.h"

#include <link/io.h>

int               RaidFoundArea(char *, char *);
int               RaidAddtoArea(struct TicStruct *, char *, char *);
int               RaidScanForPresence(struct TicStruct *, char *);
int               RaidDeletefromArea(struct TicStruct *, char *);


/// LoadDLGMAILTIC
int   LoadDLGMAILTIC()
{
   int   rc = 1;
   BPTR  fh;
   struct TicStruct *t;
   struct TicStruct *first;
   struct TicStruct *l;
   char  line[250];
   char *s;

   Log("-> Loading .TIC file");

   if (TS)
      return(0);   // something already here!
      
   // create anchor

   l = (void *) calloc(sizeof(struct TicStruct), 1);

   if (!l)
      return(0);

   s = (void *) calloc(25, 1);

   if (s)
   {
      strcpy(s, "; AreaFix (RAID) rewrite");
      l->entry = s;
   }

   first = l;

   fh = Open("FIDO:DLGMail.TIC", MODE_OLDFILE);

   if (fh)
   {
      while (s = FGets(fh,line,sizeof(line)))
      {
         s = line;
         s += strlen(line);
         s--;

         if (*s == '\n')
            *s = NULL;

         s = (void *) calloc(strlen(line) + 1, 1);

         if (s)
         {
            strcpy(s, line);

            t = (void *) calloc(sizeof(struct TicStruct), 1);

            if (!t)
            {
               rc = 0;
               break;
            }

            t->entry = s;
            l->next = t;
            l = t;
         }
         else
         {
            rc = 0;
            break;
         }
      }

      Close(fh);

      if (rc)
         TS = first;

      return (rc);
   }
   return(0);
}
//-

/// SaveDLGMAILTIC
int   SaveDLGMAILTIC()
{
   int   rc = 1;
   BPTR  fh;
   struct TicStruct   *t;

   if (TS == NULL)
      return 0;

   Log("-> Saving .TIC file");

   DeleteFile("FIDO:DLGMail.TICBAK");

   if (Rename("FIDO:DLGMail.TIC", "FIDO:DLGMail.TICBAK"))
   {
      Log(".  Renamed OK");

      fh = Open("FIDO:DLGMail.TIC", MODE_OLDFILE);

      if (fh)
      {
         for (t = TS->next;; t = t->next)
         {
            AFPrintf(NULL,fh, "%s\n", t->entry);

            if (t->next == NULL)
               break;
         }

         Close(fh);
      }
      else
      {
         Log("!  Oops, couldn't write new file");
         Rename("FIDO:DLGMail.TICBAK", "FIDO:DLGMail.TIC");
         return (0);
      }
   }
   else
   {
      return(0);
   }

   return (rc);
}
//-

/// RaidWorkArea
RaidWorkArea(char *address, char *classes, char *curarea, char *ticflags)
{
   struct TicStruct   *t;
   int   rc = -99;
   int   sc = 0;
   char  tmp[30];
   BOOL  add = TRUE;
   char  this_area_class[10];
   char *s;
   char  token[50];

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

   for (t = TS;; t = t->next)
   {
      s = t->entry;
      s = stpblk(s);
      s = stptok(s, token, sizeof(token), " \t");
      s = stpblk(s);

      if (!Stricmp(token, "AREA"))
      {
         s = stptok(s, token, sizeof(token), " \t");
         s = stpblk(s);

         if (!Stricmp(tmp, token))
         {
            AFPrintf(NULL,sout,"\tfound the area\n");

            strcpy(this_area_class, "-1");

            if (*s)
            {
                 // get the area's class

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

               if (!Stricmp(token, "CLASS"))
               {
                  s = stptok(s, token, sizeof(token), " \t");
                  s = stpblk(s);

                  strcpy(this_area_class, token);
               }
            }

            rc = RaidFoundArea(this_area_class, classes);
            AFPrintf(NULL,sout,"\tFoundArea() returned %d\n", rc);

            if (rc)
            {
               if (add)
               {
                  sc = RaidAddtoArea(t, address, ticflags);
               }
               else
               {
                  sc = RaidDeletefromArea(t, address);
                  sc *= -1;
               }
            }
            else
            {
               sc = 3;

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

            break;
         }
      }

      if (t->next == NULL)
         break;
   }

   if (sc)
      rc = sc;

   if (rc == -99)
   {
      AFPrintf(NULL,sout,"area isn't in area.bbs list\n");
   }

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

   return (rc);
}
//-

/// RaidFoundArea
RaidFoundArea(char *this_class, char *classes)
{
   char *ap;
   char  curclass[10];
   int   cc;

   ap = classes;
   ap = stpblk(ap);
   
   while (1)
   {
      if (*ap == '\n' || *ap == NULL)
         break;
   
      ap = stptok(ap, curclass, sizeof(curclass), " \t");
      ap = stpblk(ap);
      cc = atoi(curclass);

      if (atoi(this_class) == cc)
         return (1);
   }
   
   return (0);
}
//-

/// RaidAddToArea
RaidAddtoArea(struct TicStruct * t, char *address, char *ticflags)
{
   BOOL  ok;
   struct TicStruct   *r = NULL;
   struct TicStruct   *last_to = NULL;
   struct TicStruct   *insert_me;
   char *entrypointer;

   char  line_to_add[100];
   char  address_to_look_for[100];
   struct TicStruct   *remember_me;

   char  token[50];
   char *s;

   short zone, net, node, point;
   char  domain[100];
   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");

   remember_me = t;

   if (point)
   {
      ASPrintf(NULL,line_to_add, "TO %d:%d/%d.%d\t%s\t;autoadded by DLGAreaFix", zone, net, node, point, ticflags);
      ASPrintf(NULL,address_to_look_for, "%d:%d/%d.%d", zone, net, node, point);
   }
   else
   {
      ASPrintf(NULL,line_to_add, "TO %d:%d/%d\t%s\t;autoadded by DLGAreaFix", zone, net, node, ticflags);
      ASPrintf(NULL,address_to_look_for, "%d:%d/%d", zone, net, node);
   }

   presence = RaidScanForPresence(remember_me->next, address_to_look_for);

   if (presence)
   {
      return(9);
   }

   // not there, so add us

   insert_me = (void *) calloc(sizeof(struct TicStruct), 1);

   entrypointer = (void *) calloc(strlen(line_to_add) + 1, 1);

   if (insert_me == NULL || entrypointer == NULL)
   {
      AFPrintf(NULL,sout,"no mem");
         return(6);
   }

   strcpy(entrypointer, line_to_add);
   insert_me->entry = entrypointer;

   /* ok, what we have here is a pointer into the file linked
    * list pointing at the AREA XXX CLASS YY line. we need
    * to advance forward, ignoring "REPLACE" and "LOCALAREA" 
    * lines. We keep track of the last "TO" line we hit.
    * When we hit either "ANNOUNCE" or "EXECUTE" or "AREA" or
    * "IGNORE" we know we've passed all the TO lines 
    */

   /* EXCEPTION: the AREA line is the last line of the file */

   if (remember_me->next == NULL)
   {
      remember_me->next = insert_me;
      return 15;
   }

   for (r = remember_me->next;; r = r->next)
   {
      s = r->entry;
      s = stpblk(s);
      s = stptok(s, token, sizeof(token), " \t");
      s = stpblk(s);

      ok = FALSE;

      if (*token == ';'                ||
          !Stricmp(token, "REPLACE")   ||
          !Stricmp(token, "LOCALAREA") ||
          !Stricmp(token, "DESC")      ||
          !Stricmp(token, "COPYAREA")  ||
          !Stricmp(token, "PURGE"))
      {
         ok = TRUE;
         remember_me = r;
      }

      if (!Stricmp(token, "TO"))
      {
         ok = TRUE;
         last_to = r;
      }

      if (!ok || r->next == NULL)
         break;
   }

   if (last_to)
   {
      insert_me->next = last_to->next;
      last_to->next = insert_me;
      return(15);
   }

   insert_me->next = remember_me->next;
   remember_me->next = insert_me;
   return(15);
}
//-

/// RaidScanForPresence
RaidScanForPresence(struct TicStruct * r, char *address)
{
   BOOL  ok;
   char  token[50];
   char *s;
   struct TicStruct   *t;

   for (t = r;; t = t->next)
   {
      ok = FALSE;

      s = t->entry;

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

      if (*token == ';'                ||
          !Stricmp(token, "REPLACE")   ||
          !Stricmp(token, "LOCALAREA") ||
          !Stricmp(token, "DESC")      ||
          !Stricmp(token, "COPYAREA")  ||
          !Stricmp(token, "PURGE"))
      {
         ok = TRUE;
      }

      if (!Stricmp(token, "TO"))
      {
         ok = TRUE;
         s = stptok(s, token, sizeof(token), " \t");

         if (!Stricmp(token, address))
            return(1);
      }
      
      if (!ok || t->next == NULL)
         break;
   }
   return(0);
}
//-

/// RaidDeletefromArea
int RaidDeletefromArea(struct TicStruct *t, char *address)
{
   int   presence;
   char *g;
   struct TicStruct   *r;
   char  token[50];
   char *s;
   short zone, net, node, point;
   char  domain[100];
   int   code;
   char  address_to_look_for[100];

   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

   r = t;

   if (point)
   {
      ASPrintf(NULL,address_to_look_for, "%d:%d/%d.%d", zone, net, node, point);
   }
   else
   {
      ASPrintf(NULL,address_to_look_for, "%d:%d/%d", zone, net, node);
   }

   presence = RaidScanForPresence(r->next, address_to_look_for);
   
   if (!presence)
   {
      return(7);
   }

/* we know it's here so we can look for it... */

   for (;; r = r->next)
   {
      s = r->entry;

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

      if (!Stricmp(token, "TO"))
      {
         s = stptok(s, token, sizeof(token), " \t");

         if (!Stricmp(token, address_to_look_for))
         {
            g = (void *) calloc(strlen(r->entry) + 15, 1);

            if (g)
            {
               strcpy(g, ";;; ");
               strcat(g, r->entry);
               r->entry = g;
               return(16);
            }
   
            return(6);
         }
      }
   }
}
//-

/// RaidReplyReport
void  RaidReplyReport(char *reportname, char *fiveDaddr, int type, char *classes)
{
   char  domain[30];
   short zone, net, node, point;

   char  address_to_look_for[100];
   char  token[50];
   char *s;

   BPTR  fh;

   struct TicStruct   *t;

   int   IsActive;
   int   ClassOK;
   char  name[50];
   char  class[50];
   int   code;
   int   c1 = 0;
   int   c2 = 0;
   BOOL  looking_for_desc;

   Log("-> In ReplyReport()");

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

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

   if (point)
   {
      ASPrintf(NULL,address_to_look_for, "%d:%d/%d.%d", zone, net, node, point);
   }
   else
   {
      ASPrintf(NULL,address_to_look_for, "%d:%d/%d", zone, net, node);
   }

   fh = Open(reportname, MODE_READWRITE);

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

      if (type == ACTIVE)
         AFPrintf(NULL,fh, "Address [%s] active for the following FILE areas:\n\n", strchr(fiveDaddr, '!') + 1);

      if (type == AVAILABLE)
         AFPrintf(NULL,fh, "The following FILE areas are available to [%s]\n\n", strchr(fiveDaddr, '!') + 1);

      looking_for_desc = FALSE;

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

      for (t = TS;; t = t->next)
      {
         s = t->entry;
         s = stpblk(s);
         s = stptok(s, token, sizeof(token), " \t");
         s = stpblk(s);

         if (looking_for_desc)
         {
            if (!Stricmp(token, "DESC"))
            {
               AFPrintf(NULL,fh, "%-38.38s\n", s);
            }
            else
            {
               AFPrintf(NULL,fh, "\n");
            }

            looking_for_desc = FALSE;
         }

         if (!Stricmp(token, "AREA"))
         {
            s = stptok(s, token, sizeof(token), " \t");
            s = stpblk(s);
            strcpy(name, token);
            strcpy(class, "-1");

            if (*s)
            {
               s = stptok(s, token, sizeof(token), " \t");
               s = stpblk(s);

               if (!Stricmp(token, "CLASS"))
               {
                  s = stptok(s, token, sizeof(token), " \t");
                  strcpy(class, token);
               }
            }
            
            IsActive = RaidScanForPresence(t->next, address_to_look_for);
            ClassOK = RaidFoundArea(class, classes);

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

                  AFPrintf(NULL,fh, "%-25s  ", name);
                  c1++;
                  looking_for_desc = TRUE;
               }
            }

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

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

                     ttt = TRUE;
                  }

                  if (!IsActive)
                  {
                     if (ClassOK)
                        AFPrintf(NULL,fh, "    ");
   
                     ttt = TRUE;
                  }
   
                  if (ttt)
                  {
                     AFPrintf(NULL,fh, "%-25s  ", name);
                     looking_for_desc = TRUE;
                  }

                  if (IsActive)
                     c1++;

                  if (ClassOK)
                     c2++;
               }
            }
         }

         if (t->next == NULL)
            break;
      }

      AFPrintf(NULL,fh, "\n");
      AFPrintf(NULL,fh, "Key: A=Active 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("<- Returning");
}
//-
