#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <devices/timer.h>
#include <dos/dos.h>
#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>
#include <exec/libraries.h>
#include <exec/lists.h>
#include <exec/nodes.h>
#include <exec/memory.h>
#include <libraries/commodities.h>
#include <libraries/gadtools.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/intuition_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/alib_protos.h>
#include <clib/commodities_protos.h>

extern char *__montbl[];
extern char __months[];
extern char *__daytbl[];
extern struct Library *IntuitionBase;
extern struct Library *CxBase;
extern struct Library *GadToolsBase;
extern struct Library *IconBase;

static UBYTE *VersTag = "$VER: Nag 1.0  (3/9/93)";


long __stack = 4000;
char *__procname = "Nag";
long __priority = 0;
long __BackGroundIO = 0;


void main(int, char **);
ULONG Open_Window(void);
void AddEventNode(struct List *, UBYTE *);
void ChangeEventNode(struct List *, ULONG, UBYTE *);
void DeleteEventNode(struct List *, ULONG);
void SortEventList(struct List *);
void SaveEventList(struct List *);
void Close_Window(void);
void ProcessMsg(void);
ULONG getnum(char **);
void parse_mes_times(struct List *);
void subtaskcode(void);    
void Abort_TimerIO(ULONG);
void get_sys_time(ULONG *);
void calc_date(ULONG *);
ULONG calc_tsec(ULONG *);
ULONG set_timer_request(ULONG);

struct eNode {
   struct Node e_Node;        /* System Node structure */
   UBYTE  e_Data[129];         /* Node-specific data */
   ULONG  e_time;
   UBYTE  *e_msg;
};

LONG signum[] = {-1,-1,-1,-1,-1,-1,-1,-1};
ULONG sig[] = {0,0,0,0,0,0,0,0};
struct Task *maintask = NULL, *subtask = NULL;
UBYTE subtaskname[] = "Nag task";

struct Remember *rememberkey = NULL;
struct timerequest *TimerIO;
struct MsgPort *TimerMP,*broker_mp;
struct Message *TimerMSG;
struct Screen *screen;
struct Window *win;
struct Menu *menstr;
struct Gadget *glist,*gad[7];
struct List *el = NULL;
APTR *vi;

CxObj *broker, *filter, *sender, *translate;
ULONG cxsigflag;

char buf[129],title[81];
ULONG winsigflag;
char pts[] = "UMTWHFSAP0123456789/: ";
char dt[] = "#2/#3/#1", tt[] = "#5:#6M", dows[] = "UMTWHFS";
UBYTE *hotkey;
BOOL pup;

struct EasyStruct myES = {
   sizeof(struct EasyStruct),
   0,
   "Nag 1.0",
   NULL,
   "OK|Not OK"
}, about = {
   sizeof(struct EasyStruct),
   0,
   "Nag 1.0",
   "     Nag version 1.0     \n(c)1993 by David Walthour",
   "OK|OK"
};

struct NewBroker newbroker = {
    NB_VERSION,   /* nb_Version - Version of the NewBroker structure */
    "Nag",       /* nb_Name - Name Commodities uses to identify this commodity */
    "Nag v1.0",  /* nb_Title - Title of commodity that appears in CXExchange */
    "A reminder utility",  /* nb_Descr - Description of the commodity */
    NBU_UNIQUE|NBU_NOTIFY, /* nb_Unique - Tells CX not to launch another commodity with same name */
    COF_SHOW_HIDE, /* nb_Flags - Tells CX if this commodity has a window */
    0,            /* nb_Pri - This commodity's priority */
    0,            /* nb_Port - MsgPort CX talks to */
    0             /* nb_ReservedChannel - reserved for later use */
};

struct TextAttr Topaz80 = { "topaz.font", 8, 0, 0 };

#define EVT_HOTKEY 1L

void main(int argc, char **argv)
{
   int i;
   CxMsg *msg;
   char *b;
   BPTR f;
   UBYTE **ttypes;
   
   el = AllocRemember(&rememberkey,sizeof(struct List), MEMF_CLEAR);
   if (el!=NULL) {
      NewList(el);
         
      f = Open("ENV:nag.ml",MODE_OLDFILE);
      if (f==NULL) {
         f = Open("ENV:nag.ml",MODE_NEWFILE);
      }
      if (f!=NULL) {
         while(1) {
            b = FGets(f,buf,129);
            if (b==NULL) break;
            if ((buf[0]=='#')||(buf[0]==';')||(buf[0]==0)||(buf[0]=='\n')) continue;
            buf[strlen(buf)-1]=0;
            AddEventNode(el,buf);
         }
         
         Close(f);
      
         parse_mes_times(el);
      
         if (broker_mp = CreateMsgPort()) {
            newbroker.nb_Port = broker_mp;
            cxsigflag = 1L << broker_mp->mp_SigBit;
            ttypes = ArgArrayInit(argc,argv);
            newbroker.nb_Pri = (BYTE)ArgInt(ttypes, "CX_PRIORITY", 0);
            hotkey = ArgString(ttypes, "CX_POPKEY", "ctrl alt n");
            if (strcmp(strupr(ArgString(ttypes, "CX_POPUP", "YES")),"YES")==0) {
               pup = TRUE;
            }
            else {
               pup = FALSE;
            }
            if (broker = CxBroker(&newbroker, NULL)) {
               if (filter = CxFilter(hotkey)) {
                  AttachCxObj(broker, filter);
                  if (sender = CxSender(broker_mp, EVT_HOTKEY)) {
                     AttachCxObj(filter,sender);
                     if (translate = CxTranslate(NULL)) {
                        AttachCxObj(filter,translate);
                        if (!CxObjError(filter)) {
                           ActivateCxObj(broker, 1L);
                           
                           for (i=0; i<8; i++) {
                              signum[i] = AllocSignal(-1);
                              if (signum[i]==-1) break;
                           }
                           if (i!=8) {
                              for (i=0; i<8; i++) {
                                 if (signum[i]==-1) FreeSignal(signum[i]);
                              }
                           }
                           else {
                              for (i=0; i<8; i++) {
                                 sig[i] = 1L << signum[i];
                              }
                              maintask = FindTask(NULL);
                           
                              subtask = CreateTask(subtaskname,0L,subtaskcode,2000);
                              if(subtask) {
                                 ActivateCxObj(broker, 1L);
                                 ProcessMsg();
                                               Signal(subtask,sig[0]);
                                 Wait(sig[1]);
                                 Forbid();
                                 DeleteTask(subtask);
                                 Permit();
                  
                              }
                              for (i=0; i<8; i++) {
                                 FreeSignal(signum[i]);
                              }
                           }
                        }
                     }
                  }
               }
               DeleteCxObjAll(broker);
               while(msg = (CxMsg *)GetMsg(broker_mp)) {
                  ReplyMsg((struct Message *)msg);
               }
            }
            DeletePort(broker_mp);
         }
         ArgArrayDone();
      }
      FreeRemember(&rememberkey,TRUE);
   }
}

#define ENODE_ID   100       /* The type of "NameNode" */

void AddEventNode(struct List *list, UBYTE *name)
{
   struct eNode *namenode;
   UBYTE *p,*p1;

   if (( namenode = AllocRemember(&rememberkey,sizeof(struct eNode),MEMF_CLEAR) )!=0) {
      strcpy(namenode->e_Data,name);
      namenode->e_Node.ln_Name = namenode-> e_Data;
      namenode->e_Node.ln_Type = ENODE_ID;
      namenode->e_Node.ln_Pri  = 0;
      p1 = namenode->e_Data;
      p = strchr(p1,32);
      while(*p==32) p++;
      p1 = strchr(p,32);
      while(*p1==32) p1++;
      namenode->e_msg = p1;
      namenode->e_time = 0;
      AddTail((struct List *)list,(struct Node *)namenode);
   }
}

void ChangeEventNode(struct List *list, ULONG nn, UBYTE *name)
{
   struct eNode *worknode;
   UBYTE *p,*p1;
   
   worknode = (struct eNode *)(list->lh_Head);
   while (nn>0) {
      worknode = (struct eNode *)(worknode->e_Node.ln_Succ);
      nn--;
   }
   strcpy(worknode->e_Data,name);
   p1 = worknode->e_Data;
   p = strchr(p1,32);
   while(*p==32) p++;
   p1 = strchr(p,32);
   while(*p1==32) p1++;
   worknode->e_msg = p1;
}

void DeleteEventNode(struct List *list, ULONG nn)
{
   struct eNode *worknode;

   worknode = (struct eNode *)(list->lh_Head);
   while (nn>0) {
      worknode = (struct eNode *)(worknode->e_Node.ln_Succ);
      nn--;
   }
   Remove(worknode);
}

void SortEventList(struct List *list)
{
   struct eNode *n1,*n2;
   ULONG st[9],t1,t2;
   UBYTE *p,*p1;

   get_sys_time(st);
   
   n1 = (struct eNode *)(list->lh_Head);
   while(n2 = (struct eNode *)(n1->e_Node.ln_Succ)) {
      while(n2->e_Node.ln_Succ) {
         t1 = n1->e_time;
         t2 = n2->e_time;
         if (((t2<t1)&&(t2>st[0]))||((t1<st[0])&&(t2>st[0]))) {
            strcpy(buf,n2->e_Data);
            strcpy(n2->e_Data,n1->e_Data);
            strcpy(n1->e_Data,buf);
            p1 = n1->e_Data;
            p = strchr(p1,32);
            while(*p==32) p++;
            p1 = strchr(p,32);
            while(*p1==32) p1++;
            n1->e_msg = p1;
            p1 = n2->e_Data;
            p = strchr(p1,32);
            while(*p==32) p++;
            p1 = strchr(p,32);
            while(*p1==32) p1++;
            n2->e_msg = p1;
            n1->e_time = t2;
            n2->e_time = t1;
         }
         n2 = (struct eNode *)(n2->e_Node.ln_Succ);
      }
      n1 = (struct eNode *)(n1->e_Node.ln_Succ);
   }
}

void SaveEventList(struct List *list)
{
   BPTR f;
   struct eNode *wn,*nn;
   
   f = Open("ENVARC:nag.ml",MODE_NEWFILE);
   if (f!=NULL) {
      wn = (struct eNode *)(list->lh_Head); /* First node */
      while (nn = (struct eNode *)(wn->e_Node.ln_Succ)) {
         strcpy(buf,wn->e_Data);
         strcat(buf,"\n");
         FPuts(f,buf);
         wn = nn;
      }
      Close(f);
      f = Open("ENV:nag.ml",MODE_NEWFILE);
      if (f!=NULL) {
         wn = (struct eNode *)(list->lh_Head); /* First node */
         while (nn = (struct eNode *)(wn->e_Node.ln_Succ)) {
            strcpy(buf,wn->e_Data);
            strcat(buf,"\n");
            FPuts(f,buf);
            wn = nn;
         }
         Close(f);
      }
   }
}

#define WIDTH 396
#define HEIGHT 122

ULONG Open_Window(void)
{
   ULONG i;
   struct Gadget *g;
   
   static struct NewMenu mymenu[] = {
      { NM_TITLE, "Project",   0, 0, 0, 0 },
      { NM_ITEM,  "About",    "A",0, 0, 0 },
      { NM_ITEM,  NM_BARLABEL, 0, 0, 0, 0 },
      { NM_ITEM,  "Save",     "S",0, 0, 0 },
      { NM_ITEM,  "Hide",     "H",0, 0, 0 },
      { NM_ITEM,  "Quit",     "Q",0, 0, 0 },
      { NM_END,   NULL,        0, 0, 0, 0 }
   };

   static struct NewGadget ng[7];

   screen = NULL;
   vi = NULL;
   glist = NULL;
   win = NULL;
   menstr = NULL;
   
   if ((screen = LockPubScreen(NULL)) != NULL) {
      if ((vi=GetVisualInfo(screen,TAG_END)) != NULL) {
         g = CreateContext(&glist);
         
         for (i=0; i<7; i++) {
            ng[i].ng_TextAttr = &Topaz80;
            ng[i].ng_VisualInfo = vi;
            ng[i].ng_Flags = 0;
            ng[i].ng_GadgetID = i;
         }
         
         ng[0].ng_LeftEdge   = WIDTH/6 - 26;
         ng[0].ng_TopEdge    = (HEIGHT-17) + screen->WBorTop + (screen->Font->ta_YSize + 1);
         ng[0].ng_Width      = 52;
         ng[0].ng_Height     = 13;
         ng[0].ng_GadgetText = "Hide";

         ng[1].ng_LeftEdge   = WIDTH/2 - 26;
         ng[1].ng_TopEdge    = (HEIGHT-17) + screen->WBorTop + (screen->Font->ta_YSize + 1);
         ng[1].ng_Width      = 52;
         ng[1].ng_Height     = 13;
         ng[1].ng_GadgetText = "Save";

         ng[2].ng_LeftEdge   = (5*WIDTH)/6 - 26;
         ng[2].ng_TopEdge    = (HEIGHT-17) + screen->WBorTop + (screen->Font->ta_YSize + 1);
         ng[2].ng_Width      = 52;
         ng[2].ng_Height     = 13;
         ng[2].ng_GadgetText = "Quit";

         ng[3].ng_LeftEdge   = 10;
         ng[3].ng_TopEdge    = (HEIGHT-34) + screen->WBorTop + (screen->Font->ta_YSize + 1);
         ng[3].ng_Width      = 44;
         ng[3].ng_Height     = 13;
         ng[3].ng_GadgetText = "New";

         ng[4].ng_LeftEdge   = 60;
         ng[4].ng_TopEdge    = (HEIGHT-34) + screen->WBorTop + (screen->Font->ta_YSize + 1);
         ng[4].ng_Width      = 44;
         ng[4].ng_Height     = 13;
         ng[4].ng_GadgetText = "Del";

         ng[5].ng_LeftEdge   = 110;
         ng[5].ng_TopEdge    = (HEIGHT-34) + screen->WBorTop + (screen->Font->ta_YSize + 1);
         ng[5].ng_Width      = WIDTH-112;
         ng[5].ng_Height     = 13;
         ng[5].ng_GadgetText = "";
         
         ng[6].ng_LeftEdge   = 110;
         ng[6].ng_TopEdge    = 4 + screen->WBorTop + (screen->Font->ta_YSize + 1);
         ng[6].ng_Width      = WIDTH-112;
         ng[6].ng_Height     = HEIGHT-23;
         ng[6].ng_GadgetText = "Events:";
         ng[6].ng_Flags      = PLACETEXT_LEFT;
         
         gad[0] = g = CreateGadget(BUTTON_KIND,g,&ng[0],TAG_END);
         gad[1] = g = CreateGadget(BUTTON_KIND,g,&ng[1],TAG_END);
         gad[2] = g = CreateGadget(BUTTON_KIND,g,&ng[2],TAG_END);
         gad[3] = g = CreateGadget(BUTTON_KIND,g,&ng[3],TAG_END);
         gad[4] = g = CreateGadget(BUTTON_KIND,g,&ng[4],
                       GA_Disabled,       TRUE,
                       TAG_END);
         gad[5] = g = CreateGadget(STRING_KIND,g,&ng[5],
                       GTST_MaxChars,     128,
                       GA_Disabled,       TRUE,
                       TAG_END);
         gad[6] = g = CreateGadget(LISTVIEW_KIND,g,&ng[6],
                       GTLV_Labels,       el,
                       GTLV_ShowSelected, g,
                       TAG_END);

         if (g!=NULL) {
            strcpy(title,"Nag 1.0: Hot Key = <");
            strcat(title,hotkey);
            strcat(title,">");
            win = OpenWindowTags(NULL,
               WA_Title,       title,
               WA_Gadgets,     glist,
               WA_Left,        100,
               WA_Top,         60,
               WA_InnerWidth,  WIDTH,
               WA_InnerHeight, HEIGHT,
               WA_AutoAdjust,  TRUE,
               WA_DragBar,     TRUE,
               WA_DepthGadget, TRUE,
               WA_Activate,    TRUE,
               WA_CloseGadget, TRUE,
               WA_IDCMP,       IDCMP_CLOSEWINDOW   | IDCMP_MENUPICK |
                               IDCMP_REFRESHWINDOW | BUTTONIDCMP    |
                               LISTVIEWIDCMP       | STRINGIDCMP,
               WA_PubScreen,   screen,
               TAG_END);
            if (win!=NULL) {
               if (NULL!=(menstr=CreateMenus(mymenu, TAG_END))) {
                  if (LayoutMenus(menstr,vi,TAG_END)) {
                     if (SetMenuStrip(win,menstr)) {
                        GT_RefreshWindow(win,NULL);
                        return (unsigned)(1L << win->UserPort->mp_SigBit);
                     }
                     FreeMenus(menstr);
                  }
               }
               CloseWindow(win);
            }
         }
         FreeGadgets(glist);
         FreeVisualInfo(vi);
      }
      UnlockPubScreen(NULL,screen);
   }
   return 0L;
}

void Close_Window(void)
{
   FreeMenus(menstr);
   CloseWindow(win);
   FreeGadgets(glist);
   FreeVisualInfo(vi);
   UnlockPubScreen(NULL,screen);
}

void ProcessMsg(void)
{
   CxMsg *msg;
   ULONG sigrcvd, msgid, msgtype;
   LONG returnvalue = 1L;
   BOOL paused = FALSE;
   struct IntuiMessage *message;
   ULONG class;
   USHORT code;
   UWORD mennum,itnum;
   struct MenuItem *item;
   struct Gadget *g;
   LONG emn;
   

   if (pup==TRUE) {
      winsigflag = Open_Window();
      emn = -1;
   }
   else {
      winsigflag = 0;
   }

   while (returnvalue) {
      
      /* wait for something to happen */
      sigrcvd = Wait(cxsigflag|winsigflag);

      /* process any messages */
      if (sigrcvd & cxsigflag) {
         while(msg = (CxMsg *)GetMsg(broker_mp)) {
            /* Extract necessary information from the CxMessage and return it */
            msgid = CxMsgID(msg);
            msgtype = CxMsgType(msg);
            ReplyMsg((struct Message *)msg);
            switch(msgtype) {
               case CXM_IEVENT: {
                  switch(msgid) {
                     case EVT_HOTKEY: {
                        if (paused==TRUE) break;
                        if (winsigflag==0) {
                           winsigflag = Open_Window();
                           emn = -1;
                        }
                        else {
                           WindowToFront(win);
                        }
                        break;
                     }
                     default: {
                        break;
                     }
                  }
                  break;
               }
               case CXM_COMMAND: {
                  switch(msgid) {
                     case CXCMD_DISABLE: {
                        if (paused==FALSE) {
                           Signal(subtask,sig[2]);
                           Wait(sig[3]);
                        }
                        paused = TRUE;
                        ActivateCxObj(broker, 0L);
                        if (winsigflag!=0) {
                           Close_Window();
                           winsigflag = 0;
                        }
                        break;
                     }
                     case CXCMD_ENABLE: {
                        if (paused==TRUE) {
                           Signal(subtask,sig[4]);
                           Wait(sig[5]);
                        }
                        paused = FALSE;
                        ActivateCxObj(broker, 1L);
                        break;
                     }
                     case CXCMD_KILL: {
                        if (winsigflag!=0) {
                           Close_Window();
                           winsigflag = 0;
                        }
                        returnvalue = 0L;
                        break;
                     }
                     case CXCMD_APPEAR: 
                     case CXCMD_UNIQUE: {
                        if (paused==TRUE) break;
                        if (winsigflag==0) {
                           winsigflag = Open_Window();
                           emn = -1;
                        }
                        else {
                           WindowToFront(win);
                        }
                        break;
                     }
                     case CXCMD_DISAPPEAR: {
                        if (winsigflag!=0) {
                           Close_Window();
                           winsigflag = 0;
                        }
                        break;
                     }
                  }
                  break;
               }
               default: {
                  break;
               }
            }
         }
      }
      if (sigrcvd & winsigflag) {
         while (NULL != (message = GT_GetIMsg(win->UserPort))) {
            class  = message->Class;
            code   = message->Code;
            switch (class) {
               case IDCMP_CLOSEWINDOW: {
                  winsigflag = 0;
                  break;
               }
               case IDCMP_MENUPICK: {
                  while ((code != MENUNULL) && (winsigflag != 0)) {
                     item = ItemAddress(menstr,code);
                     mennum = MENUNUM(code);
                     itnum = ITEMNUM(code);
                     if (mennum==0) {
                        switch(itnum) {
                           case 0: {
                              EasyRequest(NULL,&about,NULL);
                              break;
                           }
                           case 2: {
                              SaveEventList(el);
                              break;
                           }
                           case 3: {
                              winsigflag = 0;
                              break;
                           }
                           case 4: {
                              winsigflag = 0;
                              returnvalue = 0L;
                              break;
                           }
                           default: {
                              break;
                           }
                        }
                     }
                     code = item->NextSelect;
                  }
                  break;
               }
               case IDCMP_GADGETUP: {
                  g = (struct Gadget *)message->IAddress;
                  switch(g->GadgetID) {
                     case 0: {
                        winsigflag = 0;
                        break;
                     }
                     case 1: {
                        SaveEventList(el);
                        break;
                     }
                     case 2: {
                        winsigflag = 0;
                        returnvalue = 0L;
                        break;
                     }
                     case 3: {
                        if (emn!=-2) {
                           emn = -2;
                           GT_SetGadgetAttrs(gad[4],win,NULL,GA_Disabled,FALSE,TAG_END);
                           GT_SetGadgetAttrs(gad[5],win,NULL,
                                 GA_Disabled, FALSE,
                                 GTST_String, NULL,
                                 TAG_END);
                        }
                        ActivateGadget(gad[5],win,NULL);
                        break;
                     }
                     case 4: {
                        GT_SetGadgetAttrs(gad[6],win,NULL,GTLV_Labels,~0,TAG_END);
                        if (emn!=-2) {
                           DeleteEventNode(el,emn);
                        }
                        parse_mes_times(el);
                        GT_SetGadgetAttrs(gad[6],win,NULL,GTLV_Labels,el,TAG_END);
                        emn = -1;
                        GT_SetGadgetAttrs(gad[4],win,NULL,GA_Disabled,TRUE,TAG_END);
                        GT_SetGadgetAttrs(gad[5],win,NULL,
                              GA_Disabled, TRUE,
                              GTST_String, NULL,
                              TAG_END);
                        Signal(subtask,sig[6]);
                        Wait(sig[7]);
                        break;
                     }
                     case 5: {
                        if (emn==-2) {
                           GT_SetGadgetAttrs(gad[6],win,NULL,GTLV_Labels,~0,TAG_END);
                           AddEventNode(el,((struct StringInfo *)g->SpecialInfo)->Buffer);
                           parse_mes_times(el);
                           GT_SetGadgetAttrs(gad[6],win,NULL,GTLV_Labels,el,TAG_END);
                        }
                        else {
                           GT_SetGadgetAttrs(gad[6],win,NULL,GTLV_Labels,~0,TAG_END);
                           ChangeEventNode(el,emn,((struct StringInfo *)g->SpecialInfo)->Buffer);
                           parse_mes_times(el);
                           GT_SetGadgetAttrs(gad[6],win,NULL,GTLV_Labels,el,TAG_END);
                        }
                        emn = -1;
                        GT_SetGadgetAttrs(gad[4],win,NULL,GA_Disabled,TRUE,TAG_END);
                        GT_SetGadgetAttrs(gad[5],win,NULL,
                              GA_Disabled, TRUE,
                              GTST_String, NULL,
                              TAG_END);
                        Signal(subtask,sig[6]);
                        Wait(sig[7]);
                        break;
                     }
                     case 6: {
                        emn = code;
                        GT_SetGadgetAttrs(gad[4],win,NULL,GA_Disabled,FALSE,TAG_END);
                        GT_SetGadgetAttrs(gad[5],win,NULL,GA_Disabled,FALSE,TAG_END);
                        ActivateGadget(gad[5],win,NULL);
                        break;
                     }
                     default: {
                        break;
                     }
                  }
               }
               case IDCMP_REFRESHWINDOW: {
                  GT_BeginRefresh(win);
                  GT_EndRefresh(win,TRUE);
                  break;
               }
               default: {
                  break;
               }
            }
            GT_ReplyIMsg(message);
         }
         if (winsigflag==0) {
            Close_Window();
         }
      }
   }
}

ULONG getnum(char **p)
{
   int c;
   char *s,temp[10];

   s = temp;
   while (1) {
      c = **p;
      if (isdigit(c)==0) break;
      *s = **p;
      s++;
      (*p)++;
   }
   *s = NULL;
   return strtoul(temp,NULL,10);
}

void parse_mes_times(struct List *list)
{
   int j,jj,c,flag,s,ms,ly;
   char *p,*p1;
   ULONG t[9],st[9],n;
   struct eNode *wn, *nn;
   
   get_sys_time(st);
   
   wn = (struct eNode *)(list->lh_Head); /* First node */
   while (nn = (struct eNode *)(wn->e_Node.ln_Succ)) {
      for (j=0; j<9; j++) t[j]=0;
      p = wn->e_Node.ln_Name;
      if ((*p==NULL)||(*p=='*')||(*p=='#')) {
         wn->e_time = 0;
         wn = nn;
         continue;
      }
      flag = 0;
      while (p<(wn->e_msg)) {
         c = *p;
         if (strchr(pts,toupper(c))==NULL) {
            flag = 1;
         }
         p++;
      }
      if (flag==1) {
         t[0] = 0;
         goto error;
      }
      p = wn->e_Node.ln_Name;
      while(*p==' ') p++;
      for (j=0; j<strlen(tt); j++) {
         if (tt[j]==':') {
            if (*p!=tt[j]) flag=1;
            p++;
         }
         if (tt[j]=='#') {
            c = *p;
            if (isdigit(c)) {
               n = getnum(&p);
               j++;
               jj = tt[j]-48;
               t[jj] = n;
            }
            else {
               flag=1;
               p++;
               j++;
            }
         }
         if (tt[j]=='M') {
            if (((toupper((int)*p)=='A')||(toupper((int)*p)=='P'))&&(toupper((int)*(p+1))=='M')) {
               if ((t[5]<1)||(t[5]>12)) flag=1;
               t[5] = t[5]%12;
               if (toupper((int)*p)=='P') t[5]+=12;
               p += 2;
            }
         }
      }
      if (*p==' ') {
         while(*p==' ') p++;
      }
      else {
         flag=1;
      }
      if (flag==1) {
         t[0] = 0;
         goto error;
      }
      c = *p;
      if (isdigit(c)) {
         for (j=0; j<strlen(dt); j++) {
            if (dt[j]=='/') {
               if (*p!=dt[j]) flag=1;
               p++;
            }
            if (dt[j]=='#') {
               c = *p;
               if (isdigit(c)) {
                  n = getnum(&p);
                  j++;
                  jj = dt[j]-48;
                  if ((jj==2)||(jj==3)) n--;
                  t[jj] = n;
               }
               else {
                  flag=1;
                  p++;
                  j++;
               }
            }
         }
         if (t[1]<100) t[1]+=1900;
      }
      else {
         ms = -1;
         while((strchr(dows,toupper((int)*p)))!=NULL) {
            c = *p;
            s = ((7+strlen(dows)-strlen(strchr(dows,toupper(c))))-st[4])%7;
            if (s==0) {
               if (t[5]<st[5]) {
                  s = 7;
               }
               else if (t[5]==st[5]) {
                  if (t[6]<st[6]) {
                     s = 7;
                  }
                  else if (t[6]==st[6]) {
                     if (t[7]<st[7]) {
                        s = 7;
                     }
                  }
               }
            }
            if ((ms==-1)||(s<ms)) ms = s;
            p++;
         }
         if ((*p!=' ')||(ms==-1)) flag=1;
         t[1] = st[1];
         t[2] = st[2];
         t[3] = st[3]+ms;
         ly = 0;
         if (((t[1]%4)==2)&&(t[2]==1)) ly = 1;
         if (t[3]>(__months[t[2]]+ly)) {
            t[3] -= (__months[t[2]]+ly);
            t[2] += 1;
            if (t[2]>11) {
               t[2] = 0;
               t[1] += 1;
            }
         }
      }
      if (flag==1) {
         t[0] = 0;
         goto error;
      }
      t[4] = t[7] = t[8] = 0;
      t[0] = calc_tsec(t);
      
error:
      if (t[0]<=(st[0]+2)) {
         if (t[0]==0) {
            strcpy(buf,"#");
         }
         else {
            strcpy(buf,"*");
         }
         strcat(buf,wn->e_Data);
         strcpy(wn->e_Data,buf);
         p1 = wn->e_Data;
         p = strchr(p1,32);
         while(*p==32) p++;
         p1 = strchr(p,32);
         while(*p1==32) p1++;
         wn->e_msg = p1;
         wn->e_time = 0;
      }
      else {
         wn->e_time = t[0];
      }
      wn=nn;
   }
   SortEventList(el);
}

void subtaskcode(void)
{
   BOOL notdone = TRUE;
   ULONG error,maskt,td,mtd,r;
   ULONG sigrcvd,ssigrcvd;
   ULONG st[9];
   struct eNode *wn, *nn, *mn;

   if (TimerMP = CreatePort(0,0)) {
      if (TimerIO = (struct timerequest *) CreateExtIO(TimerMP,sizeof(struct timerequest)) ) {
         if (!(error=OpenDevice( TIMERNAME, UNIT_VBLANK,(struct IORequest *) TimerIO, 0L))) {
            
            while(notdone) {
               get_sys_time(st);
               
               mn = NULL;
               mtd = -1;
               wn = (struct eNode *)(el->lh_Head); /* First node */
               while (nn = (struct eNode *)(wn->e_Node.ln_Succ)) {
                  td = (wn->e_time)-st[0];
                  if (((mn==NULL)||(td<mtd))&&(td>0)) {
                     mtd = td;
                     mn = wn;
                  }
                  wn=nn;
               }
               if (mn!=NULL) {
                  myES.es_TextFormat = mn->e_msg;
                  maskt = set_timer_request(mtd);
                  sigrcvd = Wait(maskt|sig[0]|sig[2]|sig[6]);
               }
               else {
                  sigrcvd = Wait(sig[0]|sig[2]|sig[6]);
               }
               
               if (sigrcvd & maskt) {
                  TimerMSG=GetMsg(TimerMP);
                  DisplayBeep(NULL);
                  do {
                     r = EasyRequest(NULL, &myES, NULL);
                  } while (r==0);
                  if (winsigflag!=0) {
                     GT_SetGadgetAttrs(gad[6],win,NULL,GTLV_Labels,~0,TAG_END);
                     parse_mes_times(el);
                     GT_SetGadgetAttrs(gad[6],win,NULL,GTLV_Labels,el,TAG_END);
                  }
                  else {
                     parse_mes_times(el);
                  }
               }
               if (sigrcvd & sig[0]) {
                  if (mn!=NULL) {
                     Abort_TimerIO(maskt);
                  }
                  notdone = FALSE;
               }
               if (sigrcvd & sig[2]) {
                  if (mn!=NULL) {
                     Abort_TimerIO(maskt);
                  }
                  Signal(maintask,sig[3]);
                  ssigrcvd = Wait(sig[0]|sig[4]);
                  if (ssigrcvd & sig[4]) {
                     Signal(maintask,sig[5]);
                  }
                  else if (ssigrcvd & sig[0]) {
                     notdone = FALSE;
                  }
               }
               if (sigrcvd & sig[6]) {
                  if (mn!=NULL) {
                     Abort_TimerIO(maskt);
                  }
                  Signal(maintask,sig[7]);
               }
            }

            CloseDevice((struct IORequest *) TimerIO);
         }
         DeleteExtIO((struct IORequest *) TimerIO);
      }
      DeletePort(TimerMP);
   }
   Signal(maintask,sig[1]);
   Wait(0L);
}

void get_sys_time(ULONG *t)
{
   struct timerequest *TimerIO;
   struct MsgPort *TimerMP;

   LONG error;

   if (TimerMP = CreatePort(0,0)) {
      if (TimerIO = (struct timerequest *)CreateExtIO(TimerMP,sizeof(struct timerequest)) ) {
         if (!(error=OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)TimerIO,0L))) {

            TimerIO->tr_node.io_Command = TR_GETSYSTIME;
            DoIO((struct IORequest *) TimerIO);

            t[8] = TimerIO->tr_time.tv_micro;
            t[0] = TimerIO->tr_time.tv_secs;

            calc_date(t);

            CloseDevice((struct IORequest *) TimerIO);
         }
         DeleteExtIO((struct IORequest *)TimerIO);
      }
      DeletePort(TimerMP);
   }
}

void calc_date(ULONG *t)
{
   int i;
   ULONG ly,dim;
   
   t[7] = t[0];
   t[6] = t[7]/60;
   t[5] = t[6]/60;
   t[3] = t[5]/24;
   t[7] = t[7]%60;
   t[6] = t[6]%60;
   t[5] = t[5]%24;
   t[4] = t[3]%7;
   
   t[1] = 0;
   while (t[3]>365) {
      if (t[1]%4==2) ly = 1; else ly = 0;
      t[3] -= 365+ly;
      t[1]++;
   }
   if ((t[3]==365)&&((t[1]%4)!=2)) {
      t[3] -= 365;
      t[1]++;
   }
   if (t[1]%4==2) ly = 1; else ly = 0;
   
   for (i=0; i<12; i++) {
      dim = __months[i];
      if (i==1) dim+=ly;
      if (t[3]<dim) break;
      t[3] -= dim;
   }
   t[2] = i;
   t[1] += 1978;
}

ULONG calc_tsec(ULONG *t)
{
   int i;
   ULONG yr,mo,dy,hr,mn,sc;
   
   
   yr = t[1] - 1978;
   mo = t[2];
   dy = t[3];
   hr = t[5];
   mn = t[6];
   sc = t[7];

   if ((yr<0)||(mo<0)||(dy<0)||(hr<0)||(mn<0)||(sc<0)) return 0;
   if ((mo>11)||(dy>365)||(hr>23)||(mn>59)||(sc>59)) return 0;
   if (((yr%4)!=2)&&(dy>364)) return 0;
   
   for (i=0; i<yr; i++) {
      dy += 365;
      if ((i%4)==2) dy += 1;
   }
   
   for (i=0; i<mo; i++) {
      dy += __months[i];
      if ((i==1)&&((yr%4)==2)) dy++;
   }
   
   return (dy*86400 + hr*3600 + mn*60 + sc);
}

ULONG set_timer_request(ULONG sec)
{
   TimerIO->tr_node.io_Command = TR_ADDREQUEST;
   TimerIO->tr_time.tv_secs   = sec;
   TimerIO->tr_time.tv_micro  = 0;
   TimerIO->tr_node.io_Message.mn_ReplyPort = TimerMP;
   SendIO((struct IORequest *)TimerIO);
   return (ULONG) (1L << (TimerIO->tr_node.io_Message.mn_ReplyPort->mp_SigBit));
}

void Abort_TimerIO(ULONG maskt)
{
   ULONG signals;
   
   AbortIO(TimerIO);
   WaitIO(TimerIO);
   while(1) {
      signals = SetSignal(0,0);
      if (signals & maskt) {
         SetSignal(0,maskt);
      }
      else {
         break;
      }
   }
}


