#ifndef __COMMON_H__
#include "common.h"
#endif /* __COMMON_H__ */

/* rdargs template */
#define TEMPLATE "SERVER/A,PORT/N/K,USERNAME/A,PASSWORD/A,TIME/N/K,QUIET/S,REXXPORT/K,CX_PRIORITY/N/K,CX_POPKEY/K,SPOOL/K" VERSTAG
#define OPT_SERVER   0
#define OPT_PORT     1
#define OPT_USERNAME 2
#define OPT_PASSWORD 3
#define OPT_TIME     4
#define OPT_QUIET    5
#define OPT_REXXPORT 6
#define OPT_POPKEY   7
#define OPT_PRIORITY 8
#define OPT_SPOOL    9
#define OPT_COUNT    10

LONG opts[OPT_COUNT];
typedef ULONG (*HookFunction)(VOID);

/* image data */
UWORD __chip ClockI1Data[] =
{
   /* Plane 0 */
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x8000,0x8000,0x0000,0x0000,
   0x0000,0x0000,0x8000,0x0000,0x0000,0x0000,0x0000,0x8000,
   0x0000,0x0000,0x0000,0x0000,0x8000,0x0000,0x0000,0x0000,
   0x0000,0x8000,0x0000,0x0000,0x0000,0x0000,0x8000,0x0000,
   0x0000,0x0000,0x0000,0x8000,0x0000,0x0000,0x0000,0x0000,
   0x8000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
   0x0000,0x0000,

   /* Plane 1 */
   0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
   0x0000,0x4000,0x0000,0x0000,0x0000,0x0000,0x4000,0x0000,
   0x0000,0x0000,0x0000,0x4000,0x0000,0x0000,0x0000,0x0000,
   0x4000,0x0000,0x0000,0x0000,0x0000,0x4000,0x0000,0x0000,
   0x0000,0x0000,0x4000,0x0000,0x0000,0x0000,0x0000,0x4000,
   0x0000,0x0000,0x0000,0x0000,0x4000,0x7FFF,0xFFFF,0xFFFF,
   0xFFFF,0xC000
};

/* image struct */
struct Image ClockI1 =
{
   0, 0,    /* Upper left corner */
   66, 10, 2,  /* Width, Height, Depth */
   ClockI1Data,   /* Image data */
   0x0003, 0x0000,   /* PlanePick, PlaneOnOff */
   NULL     /* Next image */
};

/* diskobject for our icon */
struct DiskObject Clock =
{
   WB_DISKMAGIC,     /* Magic Number */
   WB_DISKVERSION,      /* Version */
   {        /* Embedded Gadget Structure */
      NULL,       /* Next Gadget Pointer */
      0, 0, 66, 11,     /* Left,Top,Width,Height */
      GFLG_GADGIMAGE | GFLG_GADGHCOMP,	/* Flags */
      GACT_RELVERIFY,      /* Activation Flags */
      GTYP_BOOLGADGET,    /* Gadget Type */
      (APTR)&ClockI1,      /* Render Image */
      NULL,       /* Select Image */
      NULL,       /* Gadget Text */
      NULL,       /* Mutual Exclude */
      NULL,       /* Special Info */
      0,       /* Gadget ID */
      (APTR) 0x0001,    /* User Data (Revision) */
   },
   WBTOOL,        /* Icon Type */
   NULL,       /* Default Tool */
   NULL,       /* Tool Type Array */
   NO_ICON_POSITION, /* Current X */
   NO_ICON_POSITION, /* Current Y */
   NULL,    /* Drawer Structure */
   NULL,    /* Tool Window */
   0        /* Stack Size */
};

struct ColumnInfo ci[] =
{
   {2, "", 0},
   {30, "From", 0},
   {70, "Subject", 0},
   {-1, (STRPTR)~0, -1}
};

/* libraries & devices */
extern struct IntuitionBase *IntuitionBase;
extern struct GfxBase *GfxBase;
extern struct Library *UtilityBase;
extern struct Library *WorkbenchBase;
extern struct ExecBase *SysBase;
extern struct DosBase *DosBase;
struct Library *AmlBase;
struct Device *TimerBase;

/* variables */
struct PopData *pd;
struct Hook arthook, srvhook, IconHook;
BOOL running = FALSE;

/* batter up! */
VOID main(int argc, char **argv)
{
   BOOL ok = FALSE;
   ULONG signals, wsigs;
   APTR msg;
   struct AppMessage *amsg;

   if(pd = (struct PopData*)AllocVec(sizeof(struct PopData), MEMF_ANY | MEMF_CLEAR))
   {
      NewList(&pd->pd_List);
      pd->pd_cxPriority = CX_PRIORITY;
      pd->pd_Server[0] = '\0';
      pd->pd_Port = 110;
      pd->pd_Username[0] = '\0';
      pd->pd_Password[0] = '\0';
      pd->pd_Check = 10;
      pd->pd_TotalMsg = 0;
      pd->pd_Quiet = FALSE;
      pd->pd_InitFuel = TRUE;
      pd->pd_UseSpool = FALSE;

      if(argc != 0)
      {
         ok = fromCLI();
      }
      else
      {
         ok = fromWB((struct WBStartup*)argv);
      }

      if(ok && startUp(pd))
      {
         running = TRUE;
         while(running)
         {
            wsigs = SIGBREAKF_CTRL_C | (1UL << pd->pd_AppPort->mp_SigBit) | (1L << pd->pd_TimePort->mp_SigBit) | pd->pd_rexxSigBit | pd->pd_cxSigBit | pd->pd_HWindowSigBit | pd->pd_SharedSigBit;

            signals = Wait(wsigs);

            if(signals & (1UL << pd->pd_TimePort->mp_SigBit))
            {
               WaitIO((struct IORequest*)pd->pd_TimeRequest);

               /* do the deed */
               doPop(pd);
               initTimer(pd);
            }

            if(signals & pd->pd_cxSigBit)
            {
               while(running && (msg = GetMsg(pd->pd_cxPort)))
               {
                  running = processCxMsg(msg);
               }
            }

            if(signals & pd->pd_rexxSigBit)
            {
               CA_HandleRexx(pd->pd_ARexx);
            }

            if(signals & (1UL << pd->pd_AppPort->mp_SigBit))
            {
               while((amsg = (struct AppMessage*)GetMsg(pd->pd_AppPort)) != NULL)
               {
                  switch(amsg->am_Type)
                  {
                     case AMTYPE_APPICON:
                     {
                        switch(amsg->am_Class)
                        {
                           case AMCLASSICON_Open:
                           {
                              doPop(pd);
                              break;
                           }
                           case AMCLASSICON_Information:
                           {
                              openHWindow(pd);
                              break;
                           }
                           case AMCLASSICON_PutAway:
                           {
                              running = FALSE;
                           }
                        }
                     }
                  }
                  ReplyMsg((struct Message*)amsg);
               }
            }

            if(signals & pd->pd_HWindowSigBit)
            {
               if(!handleHWindow(pd))
               {
                  closeHWindow(pd);
               }
            }

            if(signals & SIGBREAKF_CTRL_C)
            {
               running = FALSE;
            }
         }
      }
      shutDown(pd);
      FreeVec(pd);
   }
   else
   {
      requestUser("Out of memory");
   }
}

VOID SPrintf(STRPTR buffer, STRPTR formatString,...)
{
   va_list varArgs;

   va_start(varArgs, formatString);
   vsprintf(buffer, formatString, varArgs);
   va_end(varArgs);
}

BOOL startUp(struct PopData *pd)
{
   BOOL result = FALSE;

   if(AmlBase = OpenLibrary("aml.library", 43))
   {
      if(pd->pd_TimePort = CreateMsgPort())
      {
         if(pd->pd_cxPort = CreateMsgPort())
         {
            pd->pd_cxBroker = NULL;
            pd->pd_cxSigBit = (1UL << pd->pd_cxPort->mp_SigBit);

            if(pd->pd_TimeRequest = (struct timerequest*)CreateIORequest(pd->pd_TimePort, sizeof(struct timerequest)))
            {
               if(OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest*)pd->pd_TimeRequest, 0) == 0)
               {
                  TimerBase = pd->pd_TimeRequest->tr_node.io_Device;
                  if(WorkbenchBase->lib_Version >= 44)
                  {
                     if(createCx(pd->pd_cxPort) && initARexx(pd))
                     {
                        if((pd->pd_AppPort = CreateMsgPort()) && (pd->pd_SharedPort = CreateMsgPort()))
                        {
                           pd->pd_SharedSigBit = (1L << pd->pd_SharedPort->mp_SigBit);

                           /* init the hooks */
                           arthook.h_Entry = (ULONG(*)())articlehook;
                           arthook.h_SubEntry = NULL;
                           arthook.h_Data = NULL;

                           srvhook.h_Entry = (ULONG(*)())serverhook;
                           srvhook.h_SubEntry = NULL;
                           srvhook.h_Data = NULL;

                           IconHook.h_Entry = (ULONG(*)())iconhook;
                           IconHook.h_SubEntry = NULL;
                           IconHook.h_Data = NULL;

                           if(pd->pd_AppIcon = AddAppIcon(0, 0, "IPop", pd->pd_AppPort, 0, &Clock,
                              WBAPPICONA_RenderHook, &IconHook,
                              WBAPPICONA_SupportsOpen, TRUE,
                              WBAPPICONA_SupportsInformation, TRUE,
                              WBAPPICONA_SupportsPutAway, TRUE,
                           TAG_DONE))
                           {
                              if(getScreenData(pd) && initWindow(pd) && initHWindow(pd))
                              {
                                 initTimer(pd);
                                 result = TRUE;
                              }
                           }
                        }
                     }
                  }
               }
               else
               {
                  requestUser("IPop requires workbench.library v44+");
               }
            }
            else
            {
               requestUser("Error opening timer.device");
            }
         }
      }
   }
   else
   {
      requestUser("IPop requires icon.library v44+");
   }
   return(result);
}

VOID shutDown(struct PopData *pd)
{
   if(!(IsListEmpty(&pd->pd_List)))
   {
      struct Node *node;

      while(node = RemHead(&pd->pd_List))
      {
         FreeListBrowserNode(node);
      }
      NewList(&pd->pd_List);
   }

   disposeHWindow(pd);
   disposeWindow(pd);
   freeScreenData(pd);

   if(pd->pd_AppIcon)
   {
      RemoveAppIcon(pd->pd_AppIcon);
   }

   if(pd->pd_SharedPort)
   {
      DeleteMsgPort(pd->pd_SharedPort);
   }

   if(pd->pd_AppPort)
   {
      struct AppMessage *amsg;

      while((amsg = (struct AppMessage*)GetMsg(pd->pd_AppPort)) != NULL)
      {
         ReplyMsg((struct Message*)amsg);
      }
      DeleteMsgPort(pd->pd_AppPort);
   }

   disposeARexx(pd);
   disposeCx();

   if(pd->pd_TimeRequest)
   {
      AbortIO((struct IORequest *)pd->pd_TimeRequest);
      WaitIO((struct IORequest *)pd->pd_TimeRequest);

      CloseDevice((struct IORequest*)pd->pd_TimeRequest);
      DeleteIORequest((struct IORequest*)pd->pd_TimeRequest);
   }

   if(pd->pd_cxPort)
   {
      APTR msg;

      while(msg = GetMsg(pd->pd_cxPort))
      {
         ReplyMsg(msg);
      }
      DeleteMsgPort(pd->pd_cxPort);
   }

   if(pd->pd_TimePort)
   {
      DeleteMsgPort(pd->pd_TimePort);
   }

   if(AmlBase)
   {
      CloseLibrary(AmlBase);
   }
}

BOOL getScreenData(struct PopData *pd)
{
   BOOL result = FALSE;

   if(pd->pd_Screen = LockPubScreen(NULL))
   {
      if(pd->pd_DrawInfo = GetScreenDrawInfo(pd->pd_Screen))
      {
         if(pd->pd_VisualInfo = GetVisualInfo(pd->pd_Screen, TAG_DONE))
         {
            result = TRUE;
         }
      }
   }
   return(result);
}

VOID freeScreenData(struct PopData *pd)
{
   if(pd->pd_Screen)
   {
      if(pd->pd_VisualInfo)
      {
         FreeVisualInfo(pd->pd_VisualInfo);
      }
      if(pd->pd_DrawInfo)
      {
         FreeScreenDrawInfo(pd->pd_Screen, pd->pd_DrawInfo);
      }
      UnlockPubScreen(NULL, pd->pd_Screen);
   }
}

ULONG __saveds __asm serverhook(register __a0 struct Hook *hook, register __a2 APTR data, register __a1 struct ServerProgressData *spd)
{
   UBYTE buf[256];
   ULONG array[6];

   switch(spd->spd_Type)
   {
      case SPDT_SERVER:
      {
         switch(spd->spd_Action)
         {
            case SPDA_CONNECT:
            {
               if(!pd->pd_Quiet)
               {
                  SPrintf(buf, "Connecting to %s...", pd->pd_Server);
                  SetGadgetAttrs(pd->pd_Gadgets[GID_FUEL], pd->pd_Windows[WID_MAIN], NULL,
                     GA_Text, buf,
                     FUELGAUGE_Level, 0,
                     FUELGAUGE_Max, 0,
                     FUELGAUGE_VarArgs, "",
                  TAG_DONE);
               }
               break;
            }
            case SPDA_DISCONNECT:
            {
               if(!pd->pd_Quiet)
               {
                  SPrintf(buf, "Disconnecting from %s.", pd->pd_Server);
                  SetGadgetAttrs(pd->pd_Gadgets[GID_FUEL], pd->pd_Windows[WID_MAIN], NULL,
                     GA_Text, buf,
                     FUELGAUGE_Level, 0,
                     FUELGAUGE_Max, 0,
                     FUELGAUGE_VarArgs, "",
                  TAG_DONE);
               }
               break;
            }
            case SPDA_SENDUSER:
            {
               if(!pd->pd_Quiet)
               {
                  SetGadgetAttrs(pd->pd_Gadgets[GID_FUEL], pd->pd_Windows[WID_MAIN], NULL,
                     GA_Text, "Sending Username...",
                     FUELGAUGE_Level, 0,
                     FUELGAUGE_Max, 0,
                     FUELGAUGE_VarArgs, "",
                  TAG_DONE);
               }
               break;
            }
            case SPDA_SENDPASS:
            {
               if(!pd->pd_Quiet)
               {
                  SetGadgetAttrs(pd->pd_Gadgets[GID_FUEL], pd->pd_Windows[WID_MAIN], NULL,
                     GA_Text, "Sending Password...",
                     FUELGAUGE_Level, 0,
                     FUELGAUGE_Max, 0,
                     FUELGAUGE_VarArgs, "",
                  TAG_DONE);
               }
               break;
            }
            case SPDA_POPGET:
            {
               if(spd->spd_Flags & SPDF_INITIAL)
               {
                  pd->pd_TotalMsg = spd->spd_Total;   /* total messges */
                  pd->pd_TotalSize = spd->spd_TSize;  /* total messgages size */
                  pd->pd_TotalCurrent = 0;
                  pd->pd_FirstUpdate = TRUE;
                  array[0] = 0;
                  array[1] = 0;
                  array[2] = 0;
                  array[3] = 0;
                  array[4] = 0;
                  array[5] = 0;
               }
               else if(spd->spd_Flags & SPDF_UPDATE)
               {
                  if(pd->pd_FirstUpdate)
                  {
                     pd->pd_TotalCurrent += spd->spd_TSize;
                     pd->pd_FirstUpdate = FALSE;
                  }

                  array[0] = spd->spd_Current; /* current message number */
                  array[1] = spd->spd_Total;   /* total messages */
                  array[2] = spd->spd_CSize;   /* current message transfered */
                  array[3] = spd->spd_TSize;   /* total size for this message */
                  array[4] = pd->pd_TotalCurrent; /* current of total messages size */
                  array[5] = pd->pd_TotalSize; /* total messages size */
               }
               else if(spd->spd_Flags & SPDF_END)
               {
                  pd->pd_TotalSize = 0;
                  pd->pd_TotalCurrent = 0;
                  array[0] = 0;
                  array[1] = 0;
                  array[2] = 0;
                  array[3] = 0;
                  array[4] = 0;
                  array[5] = 0;
               }

               if(!pd->pd_Quiet)
               {
                  if(pd->pd_InitFuel)
                  {
                     SetGadgetAttrs(pd->pd_Gadgets[GID_FUEL], pd->pd_Windows[WID_MAIN], NULL,
                        GA_Text, "Retrieving header %ld of %ld (%ld/%ld %ld/%ld)",
                        FUELGAUGE_Level, spd->spd_Current,
                        FUELGAUGE_Max, spd->spd_Total,
                        FUELGAUGE_VarArgs, (APTR)array,
                     TAG_DONE);

                     pd->pd_InitFuel = FALSE;
                  }
                  else
                  {
                     SetGadgetAttrs(pd->pd_Gadgets[GID_FUEL], pd->pd_Windows[WID_MAIN], NULL,
                        GA_Text, "Retrieving header %ld of %ld (%ld/%ld %ld/%ld)",
                        FUELGAUGE_Level, spd->spd_Current,
                        FUELGAUGE_VarArgs, (APTR)array,
                     TAG_DONE);
                  }
               }
               break;
            }
            case SPDA_ERROR:
            {
               if(!pd->pd_Quiet)
               {
                  SetGadgetAttrs(pd->pd_Gadgets[GID_FUEL], pd->pd_Windows[WID_MAIN], NULL,
                     GA_Text, "Error",
                     FUELGAUGE_Level, 0,
                     FUELGAUGE_Max, 0,
                     FUELGAUGE_VarArgs, "",
                  TAG_DONE);
               }
               break;
            }
         }
         break;
      }
   }
   return(0);
}

ULONG __saveds __asm articlehook(register __a0 struct Hook *hook, register __a2 APTR server, register __a1 struct ArticleDisposition *ad)
{
   STRPTR from, subject;
   struct Node *node;
   ULONG parts;
   LONG res;

   if(ad)
   {
      res = GetArticleAttrs(ad->ad_Article,
         ARTICLEA_From, &from,
         ARTICLEA_Subject, &subject,
         ARTICLEA_NumParts, &parts,
      TAG_DONE);

      if((res == 3) && (node = (struct Node*)AllocListBrowserNode(3,
         LBNA_Column, 0,
            LBNCA_CopyText, TRUE,
            LBNCA_Text, (parts > 1) ? "A" : "",
         LBNA_Column, 1,
            LBNCA_CopyText, TRUE,
            LBNCA_Text, *from ? from : (UBYTE*)"",
         LBNA_Column, 2,
            LBNCA_CopyText, TRUE,
            LBNCA_Text, *subject ? subject : (UBYTE*)"",
      TAG_DONE)))
      {
         AddTail(&pd->pd_List, node);
      }
      pd->pd_FirstUpdate = TRUE;
   }
   return(0);
}

ULONG __saveds __asm __interrupt iconhook(register __a0 struct Hook *hook, register __a2 APTR unused, register __a1 struct AppIconRenderMsg *arm)
{
   struct RastPort rp = (*arm->arm_RastPort);
   UBYTE buffer[16];
   LONG left, top;

   left = arm->arm_Left + 4;
   top = arm->arm_Top + 3;

   SPrintf(buffer, "Messages: %ld", pd->pd_TotalMsg);

   SetABPenDrMd(&rp, 2, 1, JAM2);
   RectFill(&rp, left, top, arm->arm_Width, arm->arm_Height);
   SetAPen(&rp, 2);
   Move(&rp, left, top + rp.TxBaseline);
   Text(&rp, buffer, strlen(buffer));

   return(FALSE);
}

BOOL initHWindow(struct PopData *pd)
{
   BOOL result = FALSE;

   pd->pd_Objects[OID_HEADER] = WindowObject,
      WA_Width, 400,
      WA_Height, 280,
      WA_Activate, FALSE,
      WA_CloseGadget, TRUE,
      WA_SizeGadget, TRUE,
      WA_DepthGadget, TRUE,
      WA_SizeBBottom, TRUE,
      WA_DragBar, TRUE,
      WA_ScreenTitle, VERS,
      WA_Title, "IPop Headers",
      WINDOW_AppPort, pd->pd_SharedPort,
      WINDOW_Position, WPOS_CENTERSCREEN,
      WINDOW_ParentGroup, pd->pd_Gadgets[GID_HMAIN] = LayoutObject,
         LAYOUT_SpaceOuter, TRUE,
         LAYOUT_SpaceInner, TRUE,
         LAYOUT_HorizAlignment, LAYOUT_ALIGN_TOP,
         LAYOUT_Orientation, LAYOUT_ORIENT_VERT,
         LAYOUT_DeferLayout, TRUE,

         LAYOUT_AddChild, pd->pd_Gadgets[GID_LB] = ListBrowserObject,
            GA_ID, GID_LB,
            GA_RelVerify, TRUE,
            GA_ReadOnly, TRUE,
            LISTBROWSER_ColumnInfo, &ci,
            LISTBROWSER_ColumnTitles, TRUE,
            LISTBROWSER_Labels, &pd->pd_List,
            LISTBROWSER_AutoFit, TRUE,
         ListBrowserEnd,
         CHILD_MinWidth, 400,
         CHILD_MinHeight, 250,
      LayoutEnd,
   EndWindow;

   if(pd->pd_Objects[OID_HEADER])
   {
      result = TRUE;
   }
   return(result);
}

BOOL openHWindow(struct PopData *pd)
{
   BOOL result = FALSE;

   if(pd->pd_Windows[WID_HEADER] == NULL) /* window isn't open, make it so */
   {
      if(pd->pd_Windows[WID_HEADER] = CA_OpenWindow(pd->pd_Objects[OID_HEADER]))
      {
         GetAttr(WINDOW_SigMask, pd->pd_Objects[OID_HEADER], &pd->pd_HWindowSigBit);
         result = TRUE;
      }
   }
   else
   {
      WindowToFront(pd->pd_Windows[WID_HEADER]);
      ActivateWindow(pd->pd_Windows[WID_HEADER]);
      if(pd->pd_Windows[WID_MAIN]->Flags & WFLG_ZOOMED)
      {
         ZipWindow(pd->pd_Windows[WID_HEADER]);
      }
   }
   return(result);
}

VOID closeHWindow(struct PopData *pd)
{
   if(pd->pd_Windows[WID_HEADER] != NULL)
   {
      CA_CloseWindow(pd->pd_Objects[OID_HEADER]);
      pd->pd_Windows[WID_HEADER] = NULL;
   }
}

VOID disposeHWindow(struct PopData *pd)
{
   if(pd->pd_Objects[OID_HEADER])
   {
      DisposeObject(pd->pd_Objects[OID_HEADER]);
      pd->pd_Objects[OID_HEADER] = NULL;
   }
}

BOOL handleHWindow(struct PopData *pd)
{
   ULONG result = 0UL;
   BOOL retval = TRUE;
   UWORD code;

   while((result = CA_HandleInput(pd->pd_Objects[OID_HEADER], &code)) != WMHI_LASTMSG)
   {
      switch(result & WMHI_CLASSMASK)
      {
         case WMHI_CLOSEWINDOW:
         {
            retval = FALSE;
            break;
         }

         case WMHI_GADGETUP:
         {
            switch(result & WMHI_GADGETMASK)
            {
               case GID_LB:
               {
                  break;
               }
               default:
               {
                  break;
               }
            }
            break;
         }
      }
   }
   return(retval);
}

BOOL initWindow(struct PopData *pd)
{
   BOOL result = FALSE;

   pd->pd_Objects[OID_MAIN] = WindowObject,
      WA_Activate, FALSE,
      WA_SizeBBottom, TRUE,
      WA_DepthGadget, TRUE,
      WA_DragBar, TRUE,
      WA_ScreenTitle, VERS,
      WA_Title, "IPop Status",
      WINDOW_AppPort, pd->pd_SharedPort,
      WINDOW_Position, WPOS_TOPLEFT,
      WINDOW_ParentGroup, pd->pd_Gadgets[GID_MAIN] = LayoutObject,
         LAYOUT_SpaceOuter, TRUE,
         LAYOUT_SpaceInner, TRUE,
         LAYOUT_HorizAlignment, LAYOUT_ALIGN_TOP,
         LAYOUT_Orientation, LAYOUT_ORIENT_VERT,
         LAYOUT_DeferLayout, TRUE,

         LAYOUT_AddChild, pd->pd_Gadgets[GID_FUEL] = FuelGaugeObject,
            GA_ID, GID_FUEL,
            GA_Text, "",
            FUELGAUGE_Orientation, FGORIENT_HORIZ,
            FUELGAUGE_Justification, FGJ_LEFT,
            FUELGAUGE_Min, 0,
            FUELGAUGE_Max, 100,
            FUELGAUGE_Level, 0,
            FUELGAUGE_Percent, FALSE,
            FUELGAUGE_TickSize, 5,
            FUELGAUGE_Ticks, 5,
            FUELGAUGE_ShortTicks, TRUE,
            FUELGAUGE_VarArgs, "%s",
         FuelGaugeEnd,
         CHILD_MinWidth, 275,
      LayoutEnd,
   EndWindow;

   if(pd->pd_Objects[OID_MAIN])
   {
      result = TRUE;
   }
   return(result);
}

BOOL openWindow(struct PopData *pd)
{
   BOOL result = FALSE;

   if(pd->pd_Windows[WID_MAIN] == NULL) /* window isn't open, make it so */
   {
      if(pd->pd_Windows[WID_MAIN] = CA_OpenWindow(pd->pd_Objects[OID_MAIN]))
      {
         result = TRUE;
      }
   }
   else
   {
      WindowToFront(pd->pd_Windows[WID_MAIN]);
      ActivateWindow(pd->pd_Windows[WID_MAIN]);
      if(pd->pd_Windows[WID_MAIN]->Flags & WFLG_ZOOMED)
      {
         ZipWindow(pd->pd_Windows[WID_MAIN]);
      }
   }
   return(result);
}

VOID closeWindow(struct PopData *pd)
{
   if(pd->pd_Windows[WID_MAIN] != NULL)
   {
      CA_CloseWindow(pd->pd_Objects[OID_MAIN]);
      pd->pd_Windows[WID_MAIN] = NULL;
   }
}

VOID disposeWindow(struct PopData *pd)
{
   if(pd->pd_Objects[OID_MAIN])
   {
      DisposeObject(pd->pd_Objects[OID_MAIN]);
      pd->pd_Objects[OID_MAIN] = NULL;
   }
}

BOOL doPop(struct PopData *pd)
{
   BOOL result = FALSE, ok = FALSE;
   APTR server;

   if(!pd->pd_Quiet)
   {
      if(openWindow(pd))
      {
         ok = TRUE;
      }
   }
   else
   {
      ok = TRUE;
   }

   if(ok)
   {
      if(server = CreateServer(
         SERVERA_Type, SVRTYPE_POP3,
         SERVERA_HostName, pd->pd_Server,
         SERVERA_HostPort, pd->pd_Port,
         SERVERA_UserName, pd->pd_Username,
         SERVERA_PassWord, pd->pd_Password,
         pd->pd_UseSpool ? SERVERA_SpoolFile : TAG_IGNORE, pd->pd_SpoolFile,
         SERVERA_ProgressHook, &srvhook,
      TAG_END))
      {
         struct Node *node;

         if(!(IsListEmpty(&pd->pd_List)))
         {
            SetGadgetAttrs(pd->pd_Gadgets[GID_LB], pd->pd_Windows[WID_HEADER] ? pd->pd_Windows[WID_HEADER] : NULL, NULL,
               LISTBROWSER_Labels, ~0,
               LISTBROWSER_ColumnInfo, NULL,
            TAG_DONE);

            while(node = RemHead(&pd->pd_List))
            {
               FreeListBrowserNode(node);
            }
            NewList(&pd->pd_List);

            SetGadgetAttrs(pd->pd_Gadgets[GID_LB], pd->pd_Windows[WID_HEADER] ? pd->pd_Windows[WID_HEADER] : NULL, NULL,
               LISTBROWSER_ColumnInfo, &ci,
               LISTBROWSER_ColumnTitles, TRUE,
               LISTBROWSER_AutoFit, TRUE,
               LISTBROWSER_Labels, &pd->pd_List,
            TAG_DONE);
         }

         SetGadgetAttrs(pd->pd_Gadgets[GID_LB], pd->pd_Windows[WID_HEADER] ? pd->pd_Windows[WID_HEADER] : NULL, NULL,
            LISTBROWSER_Labels, ~0,
            LISTBROWSER_ColumnInfo, NULL,
         TAG_DONE);

         GetServerArticles(server, NULL, pd->pd_UseSpool ? NULL : &arthook, pd->pd_UseSpool ? GSAF_SPOOL : NULL);
         DisposeServer(server);

         if(pd->pd_UseSpool)
         {
            getHeaders();
         }

         SetGadgetAttrs(pd->pd_Gadgets[GID_LB], pd->pd_Windows[WID_HEADER] ? pd->pd_Windows[WID_HEADER] : NULL, NULL,
            LISTBROWSER_ColumnInfo, &ci,
            LISTBROWSER_ColumnTitles, TRUE,
            LISTBROWSER_AutoFit, TRUE,
            LISTBROWSER_Labels, &pd->pd_List,
         TAG_DONE);
         result = TRUE;
      }
   }

   WorkbenchControl(NULL,
      WBCTRLA_RedrawAppIcon, pd->pd_AppIcon,
   TAG_DONE);

   if(ok && !pd->pd_Quiet)
   {
      closeWindow(pd);
   }
   return(result);
}

VOID initTimer(struct PopData *pd)
{
   pd->pd_TimeRequest->tr_node.io_Command = TR_ADDREQUEST;
   pd->pd_TimeRequest->tr_time.tv_secs = pd->pd_Check * 60;
   pd->pd_TimeRequest->tr_time.tv_micro = 0;
   SendIO((struct IORequest*)pd->pd_TimeRequest);
}

BOOL fromCLI()
{
   BOOL result = FALSE;
   struct RDArgs *rdargs;

   if(rdargs = ReadArgs(TEMPLATE, opts, NULL))
   {
      if(opts[OPT_SERVER])
      {
         strncpy(pd->pd_Server, (STRPTR)opts[OPT_SERVER], 255);
      }

      if(opts[OPT_PORT])
      {
         pd->pd_Port = *((LONG*)opts[OPT_PORT]);
      }

      if(opts[OPT_USERNAME])
      {
         strncpy(pd->pd_Username, (STRPTR)opts[OPT_USERNAME], 255);
      }

      if(opts[OPT_PASSWORD])
      {
         strncpy(pd->pd_Password, (STRPTR)opts[OPT_PASSWORD], 255);
      }

      if(opts[OPT_TIME])
      {
         pd->pd_Check = *((LONG*)opts[OPT_TIME]);
      }

      if(opts[OPT_QUIET])
      {
         pd->pd_Quiet = TRUE;
      }

      if(opts[OPT_REXXPORT])
      {
         strncpy(pd->pd_ARexxPort, (STRPTR)opts[OPT_REXXPORT], 31);
      }
      else
      {
         strcpy(pd->pd_ARexxPort, "IPOP.1");
      }

      if(opts[OPT_POPKEY])
      {
         strncpy(pd->pd_cxPopKey, (STRPTR)opts[OPT_POPKEY], 31);
      }
      else
      {
         strncpy(pd->pd_cxPopKey, CX_POPKEY, 31);
      }

      if(opts[OPT_PRIORITY])
      {
         pd->pd_cxPriority = *((LONG *)opts[OPT_PRIORITY]);
      }
      else
      {
         pd->pd_cxPriority = CX_PRIORITY;
      }
      if(opts[OPT_SPOOL])
      {
         strncpy(pd->pd_SpoolFile, (STRPTR)opts[OPT_SPOOL], 367);
         pd->pd_UseSpool = TRUE;
      }

      FreeArgs(rdargs);
      result = TRUE;
   }
   else
   {
      PrintFault(IoErr(), "IPop");
   }
   return(result);
}

BOOL fromWB(struct WBStartup *args)
{
   BOOL result = FALSE;
   struct WBArg *wbArg;
   struct DiskObject *diskObj;
   struct Library *IconBase;
   STRPTR arg;
   BPTR oldDir;

   if(args && (IconBase = OpenLibrary("icon.library", 44)))
   {
      wbArg = args->sm_ArgList;
      oldDir = CurrentDir(wbArg->wa_Lock);
      if(diskObj = GetDiskObject(wbArg->wa_Name))
      {
         if(arg = FindToolType(diskObj->do_ToolTypes, "SERVER"))
         {
            strncpy(pd->pd_Server, arg, 255);
         }

         if(arg = FindToolType(diskObj->do_ToolTypes, "PORT"))
         {
            StrToLong(arg, (LONG*)&pd->pd_Port);
         }

         if(arg = FindToolType(diskObj->do_ToolTypes, "USERNAME"))
         {
            strncpy(pd->pd_Username, arg, 255);
         }

         if(arg = FindToolType(diskObj->do_ToolTypes, "PASSWORD"))
         {
            strncpy(pd->pd_Password, arg, 255);
         }

         if(arg = FindToolType(diskObj->do_ToolTypes, "TIME"))
         {
            StrToLong(arg, (LONG*)&pd->pd_Check);
         }

         if(arg = FindToolType(diskObj->do_ToolTypes, "QUIET"))
         {
            pd->pd_Quiet = !MatchToolValue(arg, "NO");
         }

         if(arg = FindToolType(diskObj->do_ToolTypes, "REXXPORT"))
         {
            strncpy(pd->pd_ARexxPort, arg, 31);
         }
         else
         {
            strcpy(pd->pd_ARexxPort, "IPOP.1");
         }

         if(arg = FindToolType(diskObj->do_ToolTypes, "CX_POPKEY"))
         {
            strncpy(pd->pd_cxPopKey, (char*)arg, 31);
         }
         else
         {
            strncpy(pd->pd_cxPopKey, CX_POPKEY, 31);
         }

         if(arg = FindToolType(diskObj->do_ToolTypes, "CX_PRIORITY"))
         {
            StrToLong(arg, (LONG*)&pd->pd_cxPriority);
         }

         if(arg = FindToolType(diskObj->do_ToolTypes, "SPOOL"))
         {
            strncpy(pd->pd_SpoolFile, arg, 367);
            pd->pd_UseSpool = TRUE;
         }

         FreeDiskObject(diskObj);
         result = TRUE;
      }
      CurrentDir(oldDir);
      CloseLibrary(IconBase);
   }
   return(result);
}

VOID requestUser(STRPTR bodytext)
{
   struct EasyStruct est;

   if(bodytext && !pd->pd_Quiet)
   {
      est.es_StructSize   = sizeof(struct EasyStruct);
      est.es_Flags        = 0;
      est.es_Title        = "IPop Request";
      est.es_TextFormat   = bodytext;
      est.es_GadgetFormat = "Ok";

      EasyRequestArgs(NULL, &est, NULL, NULL);
   }
}

VOID getHeaders()
{
   APTR folder, server;
   struct Hook fhook = {0};

   if(server = CreateServer(
      SERVERA_Type, SVRTYPE_FILE,
      SERVERA_Directory, PathPart(pd->pd_SpoolFile),
   TAG_END))
   {
      if(folder = CreateFolder(server,
         FOLDERA_SpoolFile, pd->pd_SpoolFile,
         FOLDERA_Path, "t:",
      TAG_END))
      {
         STRPTR n;

         GetFolderAttrs(folder, FOLDERA_Name, (ULONG *)&n, TAG_DONE);

         if(ReadFolderSpool(folder, pd->pd_SpoolFile, 0))
         {
            fhook.h_Entry = (ULONG(*)())FolderHook;
            fhook.h_SubEntry = NULL;
            fhook.h_Data = NULL;

            ScanFolderIndex(folder, (struct Hook*)&fhook, NULL);
         }
         DisposeFolder(folder);
      }
      DisposeServer(server);
   }
}

ULONG __asm __saveds FolderHook(register __a0 struct Hook *hook, register __a2 APTR folder, register __a1 struct FolderIndex *fi)
{
   struct Node *node;

   if(fi)
   {
      if(node = AllocListBrowserNode(3,
         LBNA_Column, 0,
            LBNCA_CopyText, TRUE,
            LBNCA_Text, "",
         LBNA_Column, 1,
            LBNCA_CopyText, TRUE,
            LBNCA_Text, fi->fi_From,
         LBNA_Column, 2,
            LBNCA_CopyText, TRUE,
            LBNCA_Text, fi->fi_Subject,
      TAG_DONE))
      {
         AddTail(&pd->pd_List, node);
      }
   }
   return(1);
}
