#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <errno.h>

#include <jamlib/jam.h>

#include <shared/parseargs.h>
#include <shared/jblist.h>
#include <shared/jbstrcpy.h>
#include <shared/path.h>

#include <oslib/os.h>
#include <oslib/osmem.h>
#include <oslib/osfile.h>
#include <oslib/osdir.h>
#include <oslib/ospattern.h>
#include <oslib/osmisc.h>

#include <shared/storedmsg.h>
#include <shared/fidonet.h>

#include <magimail/version.h>

#ifdef PLATFORM_AMIGA
char *ver="$VER: CrashMaint "VERSION" ("__COMMODORE_DATE__")";
#endif

static size_t ptrsize = sizeof(void *);

struct Area
{
   struct Area *Next;
   char Tagname[80];
   char Path[80];
	char Messagebase[20];
   uint32_t KeepNum,KeepDays;
};

struct jbList AreaList;

struct Messagebase
{
	char *Name;
	bool (*processfunc)(struct Area *area,bool maint,bool pack,bool verbose);
};

#ifdef MSGBASE_MSG
bool ProcessAreaMSG(struct Area *area,bool maint, bool pack, bool verbose);
#endif

#ifdef MSGBASE_JAM
bool ProcessAreaJAM(struct Area *area,bool maint, bool pack, bool verbose);
#endif

struct Messagebase Messagebases[] = 
{ 
#ifdef MSGBASE_JAM
	{ "JAM", ProcessAreaJAM },
#endif

#ifdef MSGBASE_MSG
	{ "MSG", ProcessAreaMSG },
#endif								  

	{ NULL,  NULL       } 
};

#define ARG_MAINT      0
#define ARG_PACK       1
#define ARG_VERBOSE    2
#define ARG_SETTINGS   3
#define ARG_PATTERN    4

struct argument args[] =
   { { ARGTYPE_BOOL,   "MAINT",        0, NULL },
     { ARGTYPE_BOOL,   "PACK",         0, NULL },
     { ARGTYPE_BOOL,   "VERBOSE",      0, NULL },
     { ARGTYPE_STRING, "SETTINGS",     0, NULL },
     { ARGTYPE_STRING, "PATTERN",      0, NULL },
     { ARGTYPE_END,     NULL,          0, 0    } };

bool ctrlc;

void breakfunc(int x)
{
   ctrlc=TRUE;
}

/******************** *.msg *********************/

#ifdef MSGBASE_MSG

struct Msg
{
   struct Msg *Next;
   uint32_t Num,NewNum,Day;
};

struct jbList MsgList;

int Compare(const void *a1,const void *a2)
{
   struct Msg **m1,**m2;

   m1=(struct Msg **)a1;
   m2=(struct Msg **)a2;

   if((*m1)->Num > (*m2)->Num) return(1);
   if((*m1)->Num < (*m2)->Num) return(-1);
   return(0);
}

bool Sort(struct jbList *list)
{
   struct Msg *msg,**buf,**work;
   uint32_t nc;

   nc=0;

   for(msg=(struct Msg *)list->First;msg;msg=msg->Next)
      nc++;

   if(nc == 0)
      return(TRUE);

   if(!(buf=(struct Msg **)osAlloc(nc*sizeof(struct StatsNode *))))
      return(FALSE);

   work=buf;

   for(msg=(struct Msg *)list->First;msg;msg=msg->Next)
      *work++=msg;

   qsort(buf,nc,ptrsize,Compare);

   jbNewList(list);

   for(work=buf;nc--;)
      jbAddNode(list,(struct jbNode *)*work++);

   osFree(buf);

   return(TRUE);
}

void MakeFidoDate(time_t tim,char *dest)
{
   struct tm *tp;
   time_t t;
   char *monthnames[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","???"};

   t=tim;
   tp=localtime(&t);

   sprintf(dest,"%02d %s %02d  %02d:%02d:%02d",
      tp->tm_mday,
      monthnames[tp->tm_mon],
      tp->tm_year % 100,
      tp->tm_hour,
      tp->tm_min,
      tp->tm_sec);
}

char *scanfuncarea;
bool nomem;

void scanfunc(char *str)
{
   char buf[200];
   struct osFileEntry *fe;
   uint32_t num,day;
   struct Msg *msg;

   if(strlen(str) < 5)
      return;

   if(stricmp(&str[strlen(str)-4],".msg")!=0)
      return;
                                                                             
   if(atol(str) < 2)
      return;

   MakeFullPath(scanfuncarea,str,buf,200);

   if(!(fe=osGetFileEntry(buf)))
      return;

   num=atol(str);   
   day=fe->Date / (24*60*60);

   osFree(fe);

   if(!(msg=(struct Msg *)osAlloc(sizeof(struct Msg))))
   {
      nomem=TRUE;
      return;
   }

   jbAddNode(&MsgList,(struct jbNode *)msg);

   msg->Num=num;
   msg->Day=day;
}

bool ProcessAreaMSG(struct Area *area,bool maint, bool pack, bool verbose)
{
   uint32_t today,num,del,highwater,oldhighwater;
   struct Msg *msg;
   char buf[200],newbuf[200],buf2[100];
   struct StoredMsg StoredMsg;
   osFile fh;

   highwater=0;
   oldhighwater=0;

   jbNewList(&MsgList);

   printf("Processing %s...\n",area->Tagname);

   scanfuncarea=area->Path;

   if(!(osScanDir(area->Path,scanfunc)))
   {
		uint32_t err=osError();
      printf(" Error: Couldn't scan directory %s\n",area->Path);
		printf(" Error: %s\n",osErrorMsg(err));
      jbFreeList(&MsgList);
      return(TRUE);
   }

   if(nomem)
   {
      printf("Out of memory\n");
      jbFreeList(&MsgList);
      return(FALSE);
   }

   if(!Sort(&MsgList))
   {
      printf("Out of memory\n");
      jbFreeList(&MsgList);
      return(FALSE);
   }

   if(!MsgList.First)
   {
      printf(" Area is empty\n");
      return(TRUE);
   }

   if(ctrlc)
   {
      jbFreeList(&MsgList);
      return(TRUE);
   }

   MakeFullPath(area->Path,"1.msg",buf,200);

   if((fh=osOpen(buf,MODE_OLDFILE)))
   {
      if(osRead(fh,&StoredMsg,sizeof(struct StoredMsg))==sizeof(struct StoredMsg))
      {
         highwater=StoredMsg.ReplyTo;
         oldhighwater=StoredMsg.ReplyTo;
      }
      osClose(fh);
   }

   if(maint && area->KeepNum!=0)
   {
      num=0;

      for(msg=(struct Msg *)MsgList.First;msg;msg=msg->Next)
         num++;

      msg=(struct Msg *)MsgList.First;
      del=0;

      while(num>area->KeepNum && !ctrlc)
      {
         while(msg->Num==0)
            msg=msg->Next;

         sprintf(buf2,"%u.msg",msg->Num);
         MakeFullPath(area->Path,buf2,buf,200);

         if(msg->Num == highwater)
            highwater=0;

         if(verbose)
            printf(" Deleting message #%u by number\n",msg->Num);

         osDelete(buf);

         msg->Num=0;
         num--;
         del++;
      }

      if(ctrlc)
      {
         jbFreeList(&MsgList);
         return(TRUE);
      }

      printf(" %u messages deleted by number, %u messages left\n",del,num);
   }

   if(maint && area->KeepDays!=0)
   {
      del=0;
      num=0;
		
		today=time(NULL) / (24*60*60);

      for(msg=(struct Msg *)MsgList.First;msg && !ctrlc;msg=msg->Next)
      {
         if(today - msg->Day > area->KeepDays && msg->Num!=0)
         {
            sprintf(buf2,"%u.msg",msg->Num);
            MakeFullPath(area->Path,buf2,buf,200);

            if(msg->Num == highwater)
               highwater=0;

            if(verbose)
               printf(" Deleting message #%u by date\n",msg->Num);

            osDelete(buf);
            
      	    msg->Num=0;
            del++;
         }
         else
         {
            num++;
         }
      }

      if(ctrlc)
      {
         jbFreeList(&MsgList);
         return(TRUE);
      }

      printf(" %u messages deleted by date, %u messages left\n",del,num);
   }

   if(pack)
   {
      num=2;

      msg=(struct Msg *)MsgList.First;

      while(msg && !ctrlc)
      {
         while(msg && msg->Num==0)
            msg=msg->Next;

         if(msg)
         {
            msg->NewNum=num++;
            msg=msg->Next;
         }
      }
 
      for(msg=(struct Msg *)MsgList.First;msg && !ctrlc;msg=msg->Next)
         if(msg->Num!=0 && msg->Num!=msg->NewNum)
         {
            sprintf(buf2,"%u.msg",msg->Num);
				MakeFullPath(area->Path,buf2,buf,200);

            sprintf(buf2,"%u.msg",msg->NewNum);
				MakeFullPath(area->Path,buf2,newbuf,200);

            if(highwater == msg->Num)
               highwater=msg->NewNum;

            if(verbose)
               printf(" Renaming message %u to %u\n",msg->Num,msg->NewNum);

            osRename(buf,newbuf);
         }

      if(ctrlc)
      {
         jbFreeList(&MsgList);
         return(TRUE);
      }

      printf(" Area renumbered\n");
   }

   jbFreeList(&MsgList);

   if(highwater!=oldhighwater)
   {
      strcpy(StoredMsg.From,"MagiMail");
      strcpy(StoredMsg.To,"All");
      strcpy(StoredMsg.Subject,"HighWater mark");
      MakeFidoDate(time(NULL),StoredMsg.DateTime);

      StoredMsg.TimesRead=0;
      StoredMsg.DestNode=0;
      StoredMsg.OrigNode=0;
      StoredMsg.Cost=0;
      StoredMsg.OrigNet=0;
      StoredMsg.DestNet=0;
      StoredMsg.DestZone=0;
      StoredMsg.OrigZone=0;
      StoredMsg.OrigPoint=0;
      StoredMsg.DestPoint=0;
      StoredMsg.ReplyTo=highwater;
      StoredMsg.Attr=FLAG_SENT | FLAG_PVT;
      StoredMsg.NextReply=0;

      MakeFullPath(area->Path,"1.msg",buf,200);

      if((fh=osOpen(buf,MODE_NEWFILE)))
      {
         osWrite(fh,&StoredMsg,sizeof(struct StoredMsg));
         osWrite(fh,"",1);
         osClose(fh);
      }
   }

   return(TRUE);
}

#endif

/*************************** JAM ************************/

#ifdef MSGBASE_JAM

long jam_utcoffset = 0xbaadf00d;

bool ProcessAreaJAM(struct Area *area,bool maint, bool pack, bool verbose)
{
   uint32_t today,active,basenum,total,del,num,day;
   s_JamBase *Base_PS,*NewBase_PS;
   s_JamBaseHeader BaseHeader_S;
   s_JamMsgHeader	Header_S;
   s_JamSubPacket*	SubPacket_PS;
	int res,res1,res2;
	char buf[200],oldname[200],tmpname[200];
	bool firstwritten;
	char *msgtext;

   /* Some timezone tricks */

   if(jam_utcoffset == 0xbaadf00d) 
   {
      time_t t1,t2;
      struct tm *tp;

      t1=time(NULL);
      tp=gmtime(&t1);
      tp->tm_isdst=-1;
      t2=mktime(tp);
      jam_utcoffset=t2-t1;
   }
			
   printf("Processing %s...\n",area->Tagname);

   if(JAM_OpenMB(area->Path,&Base_PS))
   {
      printf(" Failed to open messagebase \"%s\"\n",area->Path);
		return(TRUE);
	}
	
	if(JAM_LockMB(Base_PS,10))
	{
		printf(" Timeout when trying to lock messagebase \"%s\"\n",area->Path);
		JAM_CloseMB(Base_PS);
		return(TRUE);
	}

   if(JAM_ReadMBHeader(Base_PS,&BaseHeader_S))
   {
      printf(" Failed to read header of messagebase \"%s\"\n",area->Path);
		JAM_UnlockMB(Base_PS);
		JAM_CloseMB(Base_PS);
      return(TRUE);
   }

   if(JAM_GetMBSize(Base_PS,&total))
   {
      printf(" Failed to get size of messagebase \"%s\"\n",area->Path);
		JAM_UnlockMB(Base_PS);
      JAM_CloseMB(Base_PS);
      return(TRUE);
   }

   basenum=BaseHeader_S.BaseMsgNum;
   active=BaseHeader_S.ActiveMsgs;
	
   if(total == 0)
   {
      printf(" Area is empty\n");
		JAM_UnlockMB(Base_PS);
		JAM_CloseMB(Base_PS);
      return(TRUE);
   }

   if(maint && area->KeepNum!=0)
   {		
		num=0;
		del=0;
		
		while(num < total && active > area->KeepNum && !ctrlc)
		{
		   res=JAM_ReadMsgHeader(Base_PS,num,&Header_S,NULL);

         if(res == 0)
			{
				/* Read success */
				
			   if(!(Header_S.Attribute & JAM_MSG_DELETED))
				{
					/* Not already deleted */

		         if(verbose)
      		      printf(" Deleting message #%u by number\n",basenum+num);
	
					Header_S.Attribute |= JAM_MSG_DELETED;
					JAM_ChangeMsgHeader(Base_PS,num,&Header_S);

					BaseHeader_S.ActiveMsgs--;
					JAM_WriteMBHeader(Base_PS,&BaseHeader_S);
					
					active--;
					del++;
				}
			}
			
			num++;
		}

      if(ctrlc)
      {
			JAM_UnlockMB(Base_PS);
			JAM_CloseMB(Base_PS);
         return(TRUE);
      }

      printf(" %u messages deleted by number, %u messages left\n",del,active);
   }

   if(maint && area->KeepDays!=0)
   {
      del=0;
      num=0;
		
      today=(time(NULL)-jam_utcoffset) / (24*60*60);

		while(num < total && !ctrlc)
		{
		   res=JAM_ReadMsgHeader(Base_PS,num,&Header_S,NULL);

         if(res == 0)
			{
				/* Read success */

				day=Header_S.DateReceived / (24*60*60);
				
				if(day == 0)
					day=Header_S.DateProcessed / (24*60*60);
				
				if(day == 0)
					day=Header_S.DateWritten / (24*60*60);

			   if(today-day > area->KeepDays && !(Header_S.Attribute & JAM_MSG_DELETED))
				{
					/* Not already deleted and too old*/

		         if(verbose)
      		      printf(" Deleting message #%u by date\n",basenum+num);
	
					Header_S.Attribute |= JAM_MSG_DELETED;
					JAM_ChangeMsgHeader(Base_PS,num,&Header_S);

					BaseHeader_S.ActiveMsgs--;
					JAM_WriteMBHeader(Base_PS,&BaseHeader_S);
					
					del++;
					active--;
				}
			}
			
			num++;
		}

      if(ctrlc)
      {
			JAM_UnlockMB(Base_PS);
			JAM_CloseMB(Base_PS);
         return(TRUE);
      }

      printf(" %u messages deleted by date, %u messages left\n",del,active);
   }

   if(pack)
   {
		strcpy(buf,area->Path);
		strcat(buf,".cmtemp");

	   if(JAM_CreateMB(buf,1,&NewBase_PS))
   	{
      	printf(" Failed to create new messagebase \"%s\"\n",buf);
			JAM_UnlockMB(Base_PS);
			JAM_CloseMB(Base_PS);
			return(TRUE);
		}

		if(JAM_LockMB(NewBase_PS,10))
		{
			printf(" Timeout when trying to lock messagebase \"%s\"\n",buf);
			JAM_UnlockMB(Base_PS);
			JAM_CloseMB(Base_PS);
			JAM_CloseMB(NewBase_PS);
			JAM_RemoveMB(NewBase_PS,buf);
			return(TRUE);
		}

		/* Copy messages */

      del=0;
      num=0;
		firstwritten=FALSE;

		BaseHeader_S.ActiveMsgs=0;
				
		while(num < total && !ctrlc)
		{
		   res=JAM_ReadMsgHeader(Base_PS,num,&Header_S,NULL);

         if(res)
			{
				if(res == JAM_NO_MESSAGE)
				{
					if(firstwritten) 
					{
						JAM_AddEmptyMessage(NewBase_PS);
					}
					else 
					{
						BaseHeader_S.BaseMsgNum++;
						del++;
					}
				}
				else
				{
		      	printf(" Failed to read message %d, cannot pack messagebase\n",num+basenum);
					JAM_UnlockMB(Base_PS);
					JAM_CloseMB(Base_PS);
					JAM_UnlockMB(NewBase_PS);
					JAM_CloseMB(NewBase_PS);
					JAM_RemoveMB(NewBase_PS,buf);
					return(TRUE);
				}
			}
			else
			{
				if(Header_S.Attribute & JAM_MSG_DELETED)
				{
					if(firstwritten) 
					{
						JAM_AddEmptyMessage(NewBase_PS);
					}
					else
					{
						BaseHeader_S.BaseMsgNum++;					
						del++;
					}
				}
				else
				{
               if(!firstwritten)
               {
                  /* Set basenum */

                  res=JAM_WriteMBHeader(NewBase_PS,&BaseHeader_S);

                  if(res)
                  {
                     printf(" Failed to write messagebase header, cannot pack messagebase\n");
                     JAM_UnlockMB(Base_PS);
                     JAM_CloseMB(Base_PS);
                     JAM_UnlockMB(NewBase_PS);
                     JAM_CloseMB(NewBase_PS);
                     JAM_RemoveMB(NewBase_PS,buf);
                     return(TRUE);
                  }

                  firstwritten=TRUE;
               }

					/* Read header with all subpackets*/

					res=JAM_ReadMsgHeader(Base_PS,num,&Header_S,&SubPacket_PS);

				   if(res)
				   {
			      	printf(" Failed to read message %d, cannot pack messagebase\n",num+basenum);
						JAM_UnlockMB(Base_PS);
						JAM_CloseMB(Base_PS);
						JAM_UnlockMB(NewBase_PS);
						JAM_CloseMB(NewBase_PS);
						JAM_RemoveMB(NewBase_PS,buf);
						return(TRUE);
					}

				   /* Read message text */

				   msgtext=NULL;

				   if(Header_S.TxtLen)
				   {
				      if(!(msgtext=osAlloc(Header_S.TxtLen)))
				      {
							printf("Out of memory\n");
				         JAM_DelSubPacket(SubPacket_PS);
							JAM_UnlockMB(Base_PS);
							JAM_CloseMB(Base_PS);
							JAM_UnlockMB(NewBase_PS);
							JAM_CloseMB(NewBase_PS);
							JAM_RemoveMB(NewBase_PS,buf);
				         return(FALSE);
						}			

				      res=JAM_ReadMsgText(Base_PS,Header_S.TxtOffset,Header_S.TxtLen,msgtext);

				      if(res)
				      {
				      	printf(" Failed to read message %d, cannot pack messagebase\n",num+basenum);
				         JAM_DelSubPacket(SubPacket_PS);
							JAM_UnlockMB(Base_PS);
							JAM_CloseMB(Base_PS);
							JAM_UnlockMB(NewBase_PS);
							JAM_CloseMB(NewBase_PS);
							JAM_RemoveMB(NewBase_PS,buf);
					      return(TRUE);
						}
			      }

					/* Write new message */

				   res=JAM_AddMessage(NewBase_PS,&Header_S,SubPacket_PS,msgtext,Header_S.TxtLen);

					if(msgtext) osFree(msgtext);
				   JAM_DelSubPacket(SubPacket_PS);

					BaseHeader_S.ActiveMsgs++;

					if(res)
					{
				      printf(" Failed to copy message %d (disk full?), cannot pack messagebase\n",num+basenum);
						JAM_UnlockMB(Base_PS);
						JAM_CloseMB(Base_PS);
						JAM_UnlockMB(NewBase_PS);
						JAM_CloseMB(NewBase_PS);
						JAM_RemoveMB(NewBase_PS,buf);
					   return(TRUE);
					}
				}
			}
			
			num++;
		}

		/* Write back header */

		BaseHeader_S.ModCounter++;

      res=JAM_WriteMBHeader(NewBase_PS,&BaseHeader_S);

     	if(res)
     	{
        	printf(" Failed to write messagebase header, cannot pack messagebase\n");
        	JAM_UnlockMB(Base_PS);
        	JAM_CloseMB(Base_PS);
        	JAM_UnlockMB(NewBase_PS);
			JAM_CloseMB(NewBase_PS);
        	JAM_RemoveMB(NewBase_PS,buf);
        	return(TRUE);
      }

		JAM_UnlockMB(Base_PS);
		JAM_CloseMB(Base_PS);

		JAM_UnlockMB(NewBase_PS);
		JAM_CloseMB(NewBase_PS);

		if(ctrlc)
		{
			JAM_RemoveMB(NewBase_PS,buf);
         return(TRUE);
      }
		
		/* This could not be done with JAMLIB... */

	   sprintf(oldname,"%s%s",area->Path,EXT_HDRFILE);
  	   sprintf(tmpname,"%s.cmtemp%s",area->Path,EXT_HDRFILE);
		res1=osDelete(oldname);
		res2=osRename(tmpname,oldname);

		if(res1 && res2)
		{
		   sprintf(oldname,"%s%s",area->Path,EXT_TXTFILE);
  		   sprintf(tmpname,"%s.cmtemp%s",area->Path,EXT_TXTFILE);
			res1=osDelete(oldname);
			res2=osRename(tmpname,oldname);
		}
		
		if(res1 && res2)
		{
	   	sprintf(oldname,"%s%s",area->Path,EXT_IDXFILE);
  	   	sprintf(tmpname,"%s.cmtemp%s",area->Path,EXT_IDXFILE);
			res1=osDelete(oldname);
			res2=osRename(tmpname,oldname);
		}
		
		if(res1 && res2)
		{
	   	sprintf(oldname,"%s%s",area->Path,EXT_LRDFILE);
  	   	sprintf(tmpname,"%s.cmtemp%s",area->Path,EXT_LRDFILE);
			/* Keep lastread file */
			res2=osDelete(tmpname);
		}
		
		if(!res1 || !res2)
		{
			printf(" Failed to update area. The area might be in use by another program.\n");
			return(FALSE);
		}

      printf(" %d deleted messages removed from messagebase\n",del);
   }
	else
	{
		JAM_UnlockMB(Base_PS);
		JAM_CloseMB(Base_PS);
	}
	
   return(TRUE);
}

#endif

/************************** end of messagebases *******************/

char cfgbuf[4000];

bool ReadConfig(char *file)
{
   osFile fh;
   char cfgword[20];
   char tag[80],aka[80],path[80],mb[20];
   struct Area *tmparea,*LastArea;
   uint32_t jbcpos;

   if(!(fh=osOpen(file,MODE_OLDFILE)))
	{
		uint32_t err=osError();
      printf("Failed to open file %s for reading\n",file);
		printf("Error: %s\n",osErrorMsg(err));
      return(FALSE);
	}
	
	LastArea=NULL;

   while(osFGets(fh,cfgbuf,4000))
   {
      jbcpos=0;
      jbstrcpy(cfgword,cfgbuf,20,&jbcpos);

      if(stricmp(cfgword,"KEEPDAYS")==0 && LastArea)
      {
         if(jbstrcpy(tag,cfgbuf,80,&jbcpos))
            LastArea->KeepDays=atol(tag);
      }

      if(stricmp(cfgword,"KEEPNUM")==0 && LastArea)
      {
         if(jbstrcpy(tag,cfgbuf,80,&jbcpos))
            LastArea->KeepNum=atol(tag);
      }

      if(stricmp(cfgword,"AREA")==0 || stricmp(cfgword,"NETMAIL")==0 || stricmp(cfgword,"LOCALAREA")==0)
      {
         jbstrcpy(tag,cfgbuf,80,&jbcpos); 
         jbstrcpy(aka,cfgbuf,80,&jbcpos);

         if(stricmp(tag,"DEFAULT")!=0 && strnicmp(tag,"DEFAULT_",8)!=0)
         {
				if(jbstrcpy(mb,cfgbuf,20,&jbcpos))
				{
				   jbstrcpy(path,cfgbuf,80,&jbcpos);
					
               if(!(tmparea=(struct Area *)osAllocCleared(sizeof(struct Area))))
               {
         		   printf("Out of memory\n");
                  osClose(fh);
                  return(FALSE);
               }                  
					
					jbAddNode(&AreaList,(struct jbNode *)tmparea);
               LastArea=tmparea;

               strcpy(tmparea->Tagname,tag);
               strcpy(tmparea->Messagebase,mb);
               strcpy(tmparea->Path,path);
            }
         }
      }
   }

   osClose(fh);
   return(TRUE);
}

int main(int argc, char **argv)
{
   struct Area *area;
   char *cfg;
   bool maint,pack,verbose;
	int i;
		
   signal(SIGINT,breakfunc);

   if(!osInit())
      exit(OS_EXIT_ERROR);

   if(argc > 1 &&
	  (strcmp(argv[1],"?")==0      ||
		strcmp(argv[1],"-h")==0     ||
		strcmp(argv[1],"--help")==0 ||
		strcmp(argv[1],"help")==0 ||
		strcmp(argv[1],"/h")==0     ||
		strcmp(argv[1],"/?")==0 ))
   {
      printargs(args);
      osEnd();
      exit(OS_EXIT_OK);
   }

   if(!parseargs(args,argc,argv))
   {
      osEnd();
      exit(OS_EXIT_ERROR);
   }

   jbNewList(&AreaList);

	maint=FALSE;
	pack=FALSE;
	verbose=FALSE;

   if(args[ARG_MAINT].data)
		maint=TRUE;
	
	if(args[ARG_PACK].data)
		pack=TRUE;

   if(args[ARG_VERBOSE].data)
		verbose=TRUE;

   if(!maint && !pack)
   {
      printf("Nothing to do.\n");
      osEnd();
      exit(OS_EXIT_OK);
   }

   if(args[ARG_PATTERN].data)
   {
      if(!(osCheckPattern((char *)args[ARG_PATTERN].data)))
      {
         printf("Invalid pattern \"%s\"\n",(char *)args[ARG_PATTERN].data);
         osEnd();
         exit(OS_EXIT_ERROR);
      }
   }
  
	cfg=getenv(OS_CONFIG_VAR);

   if(!cfg)
		cfg=OS_CONFIG_NAME;

   if(args[ARG_SETTINGS].data)
      cfg=(char *)args[ARG_SETTINGS].data;

   if(!(ReadConfig(cfg)))
   {
      jbFreeList(&AreaList);
      osEnd();
      exit(OS_EXIT_ERROR);
   }

   for(area=(struct Area *)AreaList.First;area && !ctrlc;area=area->Next)
   {
      bool match;

      match=FALSE;

      if(!args[ARG_PATTERN].data)
         match=TRUE;

      else if(osMatchPattern((char *)args[ARG_PATTERN].data,area->Tagname))
         match=TRUE;

      if(match)
      {
			for(i=0;Messagebases[i].Name;i++)
				if(stricmp(Messagebases[i].Name,area->Messagebase)==0) break;

			if(Messagebases[i].processfunc)
         {
            if(!Messagebases[i].processfunc(area,maint,pack,verbose))
               exit(OS_EXIT_ERROR);
         }
			else
			{
				printf("Cannot process area %s, messagebase %s not supported by CrashMaint\n",
					area->Tagname,
					area->Messagebase);
			}
      }
   }

   if(ctrlc)
      printf("*** User Break ***\n");

   jbFreeList(&AreaList);
   osEnd();

   exit(OS_EXIT_OK);
}
