#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <dos.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <exec/types.h>
#include <fctype.h>
#include <libraries/dosextens.h>

#include <dlg/dlg.h>
#include <dlg/msg.h>
#include <dlg/log.h>
#include <dlg/resman.h>
#include <dlg/user.h>
#include <dlg/misc.h>

#include <link/io.h>
#include <link/lang.h>

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

#include <pragmas/dlg.h>

#define LPswd "UpdateArea"

#include <private/Version.h>
#define  ObjRev "1"
const UBYTE version[]="\0$VER: UpdateAreas " BUILDVER "." ObjRev " ©" COPYRIGHT " by Digerati Dreams "__AMIGADATE__;

void  main          (int, char **);
void  Process_Area  (long, long, char);
void  Delete_Old    (long, long, long);
BOOL  CheckMessage  (char *, long, long, char);
BOOL  CheckForUser  (char *);
void  Usage         (void);
void _CXBRK         (void);


struct fido      FidoNet;
struct Msg_Area  Area;

char  ForwardPrivate = FALSE;
char  ForwardNet     = FALSE;
char  LimitedInform  = FALSE;
char  NetMatch       = TRUE;

ULONG bsize          =  0;
char *bodybuf        = NULL;

long  numusers       =  0;
char *userlist       = NULL;

long  numgroups      =  0;
char *grouplist      = NULL;

BPTR                sout;
struct  Library    *DLGBase = NULL;
char              **SA;


void main(int argc, char *argv[])

{int              fp;
 char            *s;

 ULONG            size;
 struct Group_Def Group;

 sout = Output();
 if (!(DLGBase=OpenLibrary(DLGNAME, DLGVERSION)))   exit(5);
 if (!(SA = getlang(NULL)))                         exit(5);

 while(--argc>0)
      {s = *++argv;
       if (*s++ == '-')
          {while(*s)
                {switch(*s++)
                       {case 'L':
                        case 'l':  LimitedInform++;
                                   break;

                        case 'p':
                        case 'P':  ForwardPrivate++;
                                   break;

                        case 'N':
                        case 'n':  ForwardPrivate++;
                                   ForwardNet++;
                                   break;

                        case 'A':
                        case 'a':  NetMatch=FALSE;
                                   break;

                        case 'H':
                        case 'h':  Usage();
                                  _CXBRK();
                                   break;

                         default:  Usage();
                                  _CXBRK();
                                   break;
                       }
                }
          }
      }

 AFPrintf(NULL, sout, SA[2357]);

 GetFirstStruct("dlgconfig:port/FidoNet.Settings", (char *)&FidoNet, sizeof(FidoNet));

 /* Load User List into an array */
 if (FileSize("DLGConfig:Misc/Users.bbs", &size))
    {AFPrintf(NULL, sout, SA[2358]);
    _CXBRK();
    }

 numusers = size/36L;

 if (!(userlist = malloc(size)))
    {AFPrintf(NULL, sout, SA[2359]);
    _CXBRK();
    }
 GetFirstStruct("DLGConfig:Misc/Users.bbs", userlist, size);


 /* Load Group List into an array */
 if (!FileSize("DLGConfig:Group/Group.bbs", &size))
    {numgroups = size/(long)sizeof(Group);

     if (!(grouplist = malloc(numgroups*36)))
        {AFPrintf(NULL, sout, SA[2360]);
        _CXBRK();
        }
    }

 if (grouplist)
    {long counter = 0;

     if ((fp=open("DLGConfig:Group/Group.bbs",O_RDONLY))==EOF)  _CXBRK();
     AFPrintf(NULL, sout, SA[2361]);
     while(read(fp,&Group,sizeof(Group))==sizeof(Group))
          {AFPrintf(NULL, sout, SA[2362],Group.name);
           strcpy(grouplist+counter,Group.name);
           counter += 36;
          }
     close(fp);
    }

 AFPrintf(NULL, sout, SA[2363]);
 if ((fp = open("MSG:Area.bbs",O_RDONLY)) == EOF)
    {AFPrintf(NULL, sout, SA[2364]);
    _CXBRK();
    }

 while((read(fp,&Area,sizeof(Area))) == sizeof(Area))
      {if (Area.Flag & NETMAIL_AREA || Area.Flag & ECHO_AREA)
          {signal(SIGINT, SIG_DFL);
           Chk_Abort();
           signal(SIGINT, SIG_IGN);

           while(EnterArea(Area.Number, MSGLOCK | WRITELOCK) != RMNOERR)
                 Delay(250L);

           Process_Area(Area.Number,Area.Capacity,Area.Flag&NETMAIL_AREA);
           LeaveArea(Area.Number,MSGLOCK|WRITELOCK);
          }
      }
 close(fp);

 AFPrintf(NULL, sout, "\n\n");
_CXBRK();
}


void Process_Area(long number, long cap, char net)

{char  highwater[128];

 long  lomes;
 long  himes;
 long  activity = 0;

 AFPrintf(NULL, sout, SA[2365], number);

 GetHiLowPointers(number, NULL, &lomes, &himes, LPswd);

 AFPrintf(NULL, sout, SA[2366]);

 himes++;
 ASPrintf(NULL, highwater, "MSG:%d/%d.msg", number, himes);
 while(Exists(highwater))
      {CheckMessage(highwater, himes, number, net);
       himes++;
       activity = 1;
       ASPrintf(NULL, highwater,"MSG:%d/%d.msg",number,himes);
      }
 himes--;

 if ((lomes < himes-cap) && lomes>1)
    {AFPrintf(NULL, sout, SA[2367]);
     Delete_Old(number, lomes, himes-cap);
     lomes    = himes - cap;
     activity =      1;
    }

 if (!activity)
    {AFPrintf(NULL, sout, SA[2368]);
     return;
    }

 if (lomes < 2 && himes > 1)  lomes = 2;

 PutHiLowPointers((USHORT)number, NULL, lomes, himes, LPswd);
}


void Delete_Old(long number, long start, long end)

{char   filename[255];
 char   wmname  [64];

 struct Msg_Header  header;
 struct WaitingMail WM;

 if (start>2)  start--;

 for(; start <= end; start++)
    {AFPrintf(NULL, sout, SA[2371],start);

     ASPrintf(NULL, filename,  "MSG:%d/%d.msg", number, start);
     BorrowArea(number, LPswd, "Deleting Message", 64, MSGLOCK | WRITELOCK);

     /* Delete waiting mail entry if it exists */
     if (!GetFirstStruct(filename, (char *)&header, sizeof(header)))
         if (CheckForUser(header.To) && !(header.Attribute&Received))
            {ASPrintf(NULL, wmname,"USER:%s/WaitingMail.dat",header.To);
             UnderScore(wmname);
             ASPrintf(NULL, WM.msgid,"%04d:%05d",number,start);
             DeleteStruct(wmname, (char *)&WM, sizeof(WM), 11);
            }

     DeleteFile(filename);
     FreeArea(number, LPswd, MSGLOCK|WRITELOCK);
     AFPrintf(NULL, sout, SA[2372]);
    }
}


BOOL CheckMessage(char *filename, long message, long area, char net)

{struct Msg_Header Header;
 int               fp;
 char              diverted = 0;

 AFPrintf(NULL, sout, SA[2371], message);
 BorrowArea(area, LPswd, "Updating Message", 64, MSGLOCK | WRITELOCK);

 if ((fp=open(filename,O_RDONLY))==EOF)
    {FreeArea(area, LPswd, MSGLOCK | WRITELOCK);
     AFPrintf(NULL, sout, SA[2372]);
     return(-1);
    }

 read(fp, &Header, sizeof(Header));
 if (!CheckForUser(Header.To))
    {close(fp);
     FreeArea(area, LPswd, MSGLOCK | WRITELOCK);
     AFPrintf(NULL, sout, SA[2372]);
     return(-1);
    }

 if (LimitedInform && !net)
    {char areafile[64];
     char name[37];

     strcpy(name, Header.To);
     Upper(name);

     ASPrintf(NULL, areafile, "MSG:%d/User.msg", area);

     if (GetStruct(areafile, name, 36, 36))
        {close(fp);
         FreeArea(area,LPswd,MSGLOCK|WRITELOCK);
         AFPrintf(NULL, sout, SA[2372]);
         return(-1);
        }
    }

 if (net && ((Header.DestNet==FidoNet.net && Header.DestNode==FidoNet.node) || !NetMatch) && !(Header.Attribute&Local))
    if ((ForwardPrivate && Header.Attribute&Private) || ForwardNet)
       {ULONG  size;

        FileSize(filename, &size);
        size -= sizeof(Header);

        if (bsize < size)
           {if (bsize)
               {free(bodybuf);
                bsize = 0;
               }

            if (!(bodybuf = malloc(size+1)))
               {FreeArea(area, LPswd, MSGLOCK | WRITELOCK);
                return(-1);
               }

            bsize = size;
           }

        read(fp, bodybuf, size);
        bodybuf[size] = 0;
        diverted = SendPrivateMsg(&Header,bodybuf,PRINET_MSG,LPswd,"XXX");
       }

 close(fp);
 FreeArea(area,LPswd,MSGLOCK|WRITELOCK);

 if (Stricmp(Header.To,"all") && !diverted)
     WaitingMail(Header.To, Header.From, Header.Title, Area.Number, Area.Name, message, NULL);

 AFPrintf(NULL, sout, SA[2372]);
 return(0);
}


BOOL CheckForUser(char *name)

{if (DLGBinSearch(userlist,name,36,36,numusers))        return(TRUE);

 if (grouplist)
     if (DLGBinSearch(grouplist,name,36,36,numgroups))  return(TRUE);

 return(FALSE);
}


void Usage()

{AFPrintf(NULL, sout, SA[2373]);
 AFPrintf(NULL, sout, SA[2374]);
 AFPrintf(NULL, sout, SA[2375]);
 AFPrintf(NULL, sout, SA[2376]);
 AFPrintf(NULL, sout, SA[2377]);
 return;
}


void _CXBRK()

{CloseLibrary(DLGBase);

 if (bsize)      free(bodybuf);
 if (grouplist)  free(grouplist);
 if (userlist)   free(userlist);

 exit(0);
}
