#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <dialog/msg.h>

#include <proto/dos.h>
#include <proto/dlg.h>


extern struct Library  *DLGBase;
extern char           **SA;
extern struct USER_DATA StUser;

struct Integer {USHORT value;
               };

int AddGlobalAreas(char *name,int oldlevel,int newlevel,unsigned char mode,char *areafile)

{char   filename[128];
 char   userfile[128];
 int    ap;
 int    gp;

 BOOL   newscan = FALSE;
 struct Msg_Area Area;
 struct Msg_Log  Log;

 ULONG  size;
 struct Integer *areaarray;
 struct Integer *currentarray;

 long   numcurrent = 0;
 long   numnew     = 0;
 long   counter;


 if (mode & 128)
    {mode -= 128;
     newscan++;
    }

 if (mode==0)  ASPrintf(NULL, filename,"User:%s/GlobalAreas.msg",name);
 if (mode==2)  ASPrintf(NULL, filename,"User:%s/GlobalAreas.archive",name);
 if (mode==1)  ASPrintf(NULL, filename,"User:%s/GlobalAreas.file",name);
 UnderScore(filename);

 FileSize(areafile, &size);
 if ((ap=open(areafile, O_RDONLY)) == EOF)
    {AFPrintf(&StUser, Output(), SA[3452]);
     return(-1);
    }

 if (newscan)
    {/* Allocate enough memory to hold all areas in the area.bbs file */
     if(!(areaarray = (struct Integer *)malloc(2*(size/(long)sizeof(Area)))))
          return(-1);

     /* Get the size of the existing global areas file */
     if (FileSize(filename, &size)==-1)  size = 0;
     numcurrent = size / sizeof(struct Integer);

     if (!size)  size = 2;

     /* Allocate memory to hold the existing global area array */
     if (!(currentarray = (struct Integer *)malloc(size)))
        {free(areaarray);
         return(-1);
        }

     /* Open and read the file if it exists */
     if ((gp = open(filename,O_RDONLY))!=EOF)
        {read(gp, currentarray, size);
         close(gp);
        }
    }

 /* Main Loop - Read from the Area list file */
 while(read(ap,&Area,sizeof(Area))==sizeof(Area))
      {/* Calculate the Log filename */
       if (mode==0 || mode==2)
           ASPrintf(NULL, userfile,"MSG:%d/User.msg",Area.Number);
         else
           ASPrintf(NULL, userfile,"FILE:%d/User.file",Area.Number);

       strcpy(Log.Name, name);
       /* If user used to have auto access, but no longer does, remove him from the area */
       if ((oldlevel>=Area.llevel && oldlevel<=Area.ulevel) && (newlevel<Area.llevel || newlevel>Area.ulevel) && newlevel!=255)
          {/* First check to see if he has special access in that area */
           GetStruct(userfile,(char *)&Log, sizeof(Log), 36);

           /* If he does not have special access to the area, delete the user from the area, and then patch his current array of areas */
           if (!Log.special)  
              {DeleteStruct(userfile,(char *)&Log,sizeof(Log),36);
               for(counter=0;counter<numcurrent;counter++)
                  {if (Area.Number==(currentarray+counter)->value)
                      {movmem(currentarray+counter+1,currentarray+counter,(numcurrent-counter-1)*sizeof(struct Integer));
                       numcurrent--;
                      }
                  }
              }

          }

       if (newscan && oldlevel!=newlevel)
          {char foundflag = FALSE;

           /* If not a sysop, and not an auto access area, check log to see if user exists in area */
           if (newlevel!=255 && !(Area.Flag&AUTO_ACCESS_AREA) && GetStruct(userfile,(char *)&Log,sizeof(Log),36)==-1)
               continue;

           /* If not a sysop, and it is an auto access area, and his new level does not allow him into the area, then loop */
           if (newlevel!=255 && Area.Flag&AUTO_ACCESS_AREA && (newlevel<Area.llevel || newlevel>Area.ulevel))
               continue;

           /* if previous user level is not sysop, and he could get into the area before, then loop (doesn't need to be added again */
           if (oldlevel!=255 && (oldlevel>=Area.llevel && oldlevel) && oldlevel<=Area.ulevel)
               continue;

           /* Loop to see if the area about to be added is already present in his current list, and set foundflag if it is */
           for(counter=0;counter<numcurrent;counter++)
              {if (Area.Number==(currentarray+counter)->value)
                  {foundflag++;
                   break;
                  }
              }

           /* If it is not in the list, add it */
           if (!foundflag)
              {(areaarray+numnew)->value = Area.Number;
                numnew++;
              }
          }
      }

 close(ap);

 if (newscan)
    {DeleteFile(filename);

     if ((gp=open(filename,O_RDWR+O_CREAT))!=EOF)
        {if (numcurrent)
             write(gp, currentarray, numcurrent*sizeof(struct Integer));
         write(gp, areaarray, numnew*sizeof(struct Integer));    
         close(gp);

         free(areaarray);
         free(currentarray);
        }
    }

 return(0);
}
