home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Reference / DevCon / Atlanta_1990 / Atlanta-Devcon.2 / AppShell / examples / WatchMan / fn_handler.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-26  |  27.2 KB  |  901 lines

  1. /*
  2.  * Copyright (C) 1990 Commodore-Amiga, Inc.
  3.  * All rights reserved
  4.  */
  5.  
  6. /*
  7.  * $Id: fn_handler.c,v 1.11 90/06/23 13:29:46 ewout Exp Locker: ewout $
  8.  * 
  9.  */
  10.  
  11. /*
  12.  * Example handler for AppShell.
  13.  * 
  14.  * Handler sets up a process and lets the application/user have a file polled
  15.  * with a specified interval. Applictation is expected to supply the address
  16.  * of a function, which will be called in case of a change in the file
  17.  * status.
  18.  * 
  19.  * Note that this is just an example handler with a lot of overhead for
  20.  * file notification.
  21.  * 
  22.  */
  23.  
  24. #include <libraries/appshell.h>
  25. #include <dos/dostags.h>
  26. #include <dos/dosextens.h>
  27. #include <devices/timer.h>
  28. #include <string.h>
  29. #include "fn_handler.h"
  30. #include "fn_error.h"
  31.  
  32. #include <clib/appshell_protos.h>
  33. #include <clib/alib_protos.h>
  34. #include <clib/exec_protos.h>
  35. #include <clib/dos_protos.h>
  36.  
  37.  
  38.  
  39. /* I N T E R N A L  F U N C T I O N  P R O T O T Y P E S */
  40.  
  41. void __saveds   FileNotifier(void);
  42. struct TargetNode *FindTarget(struct MinList * list, UBYTE * name);
  43. struct TargetNode *AllocNodeMem(UBYTE * filename, struct PoolHeader * ph);
  44. void            FreeNodeMem(struct TargetNode * node, struct PoolHeader * ph);
  45. struct Process *__stdargs CreateAProcess(ULONG firsttag,...);
  46.  
  47. struct MsgHandler *setup_fnA(struct AppInfo *, struct TagItem *);
  48. BOOL            open_fn(struct AppInfo *, struct MsgHandler *, struct TagItem *);
  49. BOOL            handle_fn(struct AppInfo *, struct MsgHandler *, struct TagItem *);
  50. BOOL            close_fn(struct AppInfo *, struct MsgHandler *, struct TagItem *);
  51. BOOL            shutdown_fn(struct AppInfo *, struct MsgHandler *, struct TagItem *);
  52. void            FileNotifyA(struct AppInfo *, STRPTR, struct TagItem *);
  53.  
  54. /* The message structure passed to the process to exchange
  55.  * port addresses.
  56.  */
  57. struct StartUpMessage {
  58.     struct Message  su_Msg;
  59.     struct MsgPort *su_Port;
  60.     LONG            su_Error;
  61. };
  62.  
  63. /* node for the hitlist maintained by the process */
  64. struct TargetNode {
  65.     struct MinNode  tnm_Node;
  66.     struct timerequest *fntr;
  67.     struct SIPCMessage *ntfymsg;
  68.     struct FNData  *fndata;
  69.     LONG            FileSize;
  70.     struct DateStamp datestamp;
  71. };
  72.  
  73. #define FNotifyID       APSH_FN_ID+1
  74. #define FN_NOTIFICATION APSH_FN_ID+2
  75.  
  76. #define FN_SHUTDOWN     5
  77.  
  78. /* Function address for NOTIFICATION will be supplied in setup_fnA */
  79. struct Funcs    fn_funcs[] =
  80. {
  81.     {"NOTIFY", FileNotifyA, FNotifyID,},
  82.     {"NOTIFICATION", 0L, FN_NOTIFICATION, NULL, NULL, APSH_FF_PRIVATE,},
  83.     {NULL, NO_FUNCTION,}
  84. };
  85.  
  86.  
  87. struct MsgHandler *
  88. setup_fnA(struct AppInfo * ai, struct TagItem * tl)
  89. {
  90.     struct MsgHandler *mh;
  91.     struct MHObject *mho;
  92.     struct FNInfo  *fni;
  93.     struct Process *mp;
  94.     struct MsgPort *port;
  95.     struct StartUpMessage *sumsg;
  96.     ULONG           hstatus;
  97.     BOOL            FAILED = TRUE;
  98.  
  99.     ai->ai_TextRtn = NULL;
  100.  
  101.     /* Allocate all we need to get going */
  102.  
  103.     /* Get some memory */
  104.     if (mh = (struct MsgHandler *)
  105.     AllocVec(sizeof(struct MsgHandler) +
  106.          sizeof(struct FNInfo) +
  107.          sizeof(struct SIPCMessage) +
  108.          sizeof(struct FNData) +
  109.          sizeof(ULONG) * 4, MEMF_CLEAR | MEMF_PUBLIC)) {
  110.     mho = &(mh->mh_Header);
  111.         /* It's a handler so the Type is handler type and the
  112.          * priority handler priority.
  113.          */
  114.     mho->mho_Node.ln_Type = MH_HANDLER_T;
  115.     mho->mho_Node.ln_Pri = MH_HANDLER_P;
  116.         /* Give the handler a name */
  117.     mho->mho_Node.ln_Name = "FN";
  118.     NewList(&(mho->mho_ObjList));
  119.         /* Give the handler an ID */
  120.     mho->mho_ID = APSH_FN_ID;
  121.         /* Inititally the handler is closed and disabled */
  122.     mho->mho_Status = (MHS_ENABLED | MHS_CLOSE);
  123.     mho->mho_SysData = fni = MEMORY_FOLLOWING(mh);
  124.     fni->fni_sipcmsg = MEMORY_FOLLOWING(fni);
  125.     fni->fni_fndata = MEMORY_FOLLOWING(fni->fni_sipcmsg);
  126.     mh->mh_NumFuncs = 4;
  127.     mh->mh_Func = MEMORY_FOLLOWING(fni->fni_fndata);
  128.     if (fni->fni_clientport = CreatePort(0, 0)) {
  129.         if (fni->fni_replyport = CreatePort(0, 0)) {
  130.         /* Fire up process */
  131.         if (mp = (struct Process *)
  132.             CreateAProcess(NP_Entry, FileNotifier,
  133.                    NP_Name, "File Notify",
  134.                    NP_StackSize, 8000,
  135.                    NP_Priority, 5,
  136.                    TAG_END)) {
  137.             sumsg = AllocVec(sizeof(struct StartUpMessage), MEMF_CLEAR);
  138.             sumsg->su_Msg.mn_Node.ln_Type = NT_MESSAGE;
  139.             sumsg->su_Msg.mn_Length = sizeof(struct StartUpMessage);
  140.             sumsg->su_Msg.mn_ReplyPort = fni->fni_replyport;
  141.             sumsg->su_Port = fni->fni_clientport;
  142.             port = &(mp->pr_MsgPort);
  143.             PutMsg((struct MsgPort *) port, (struct Message *) sumsg);
  144.             WaitPort(fni->fni_replyport);
  145.             while (GetMsg(fni->fni_replyport));
  146.             if (sumsg->su_Error == RETURN_OK) {
  147.             FAILED = FALSE;
  148.             fni->fni_fnport = sumsg->su_Port;
  149.             }
  150.             FreeVec(sumsg);
  151.         }
  152.         }
  153.     }
  154.     }
  155.     /* Hmmm. Oh well. */
  156.     if (FAILED) {
  157.     if (mh) {
  158.         if (fni->fni_clientport) {
  159.         if (fni->fni_replyport)
  160.             DeletePort(fni->fni_replyport);
  161.         DeletePort(fni->fni_clientport);
  162.         }
  163.         FreeVec(mh);
  164.         mh = NULL;
  165.     }
  166.     ai->ai_Pri_Ret = RETURN_FAIL;
  167.     ai->ai_Sec_Ret = APSH_CLDNT_INIT_MSGH;
  168.     ai->ai_TextRtn = PrepText(ai, APSH_MAIN_ID, ai->ai_Sec_Ret, "File Notification");
  169.     } else {
  170.     hstatus = GetTagData(APSH_Status, NULL, tl);
  171.         /* Declare the handler active if so defined in initialisation */
  172.     if (hstatus & P_ACTIVE)
  173.         open_fn(ai, mh, tl);
  174.  
  175.         /* Store the address of the basic handlers functions in the
  176.          * message handler structure.
  177.          */
  178.     mh->mh_Func[MH_OPEN] = open_fn;
  179.     mh->mh_Func[MH_HANDLE] = handle_fn;
  180.     mh->mh_Func[MH_CLOSE] = close_fn;
  181.     mh->mh_Func[MH_SHUTDOWN] = shutdown_fn;
  182.     mh->mh_SigBits = (1L << fni->fni_clientport->mp_SigBit);
  183.     mh->mh_DefText = FN_ErrorMsgs;
  184.     /*
  185.      * Get address of appliction function to call, use donothing
  186.      * (StubFunc()) if not supplied
  187.      */
  188.     fn_funcs[1].fe_Func = (VOID *) GetTagData(APSH_CmdData, (ULONG) StubFunc, tl);
  189.     AddFuncEntries(ai, fn_funcs);
  190.     }
  191.     return (mh);
  192. }
  193.  
  194.  
  195. /* Enable handler */
  196. BOOL
  197. open_fn(struct AppInfo * ai, struct MsgHandler * mh, struct TagItem * tl)
  198. {
  199.     struct MHObject *mho = &(mh->mh_Header);
  200.  
  201.     mho->mho_Status &= ~MHS_CLOSE;
  202.     mho->mho_Status |= MHS_OPEN;
  203.  
  204.     return (TRUE);
  205. }
  206.  
  207. /* Disable handler */
  208. BOOL
  209. close_fn(struct AppInfo * ai, struct MsgHandler * mh, struct TagItem * tl)
  210. {
  211.     struct MHObject *mho = &(mh->mh_Header);
  212.  
  213.     mho->mho_Status &= ~MHS_OPEN;
  214.     mho->mho_Status |= MHS_CLOSE;
  215.  
  216.     return (TRUE);
  217. }
  218.  
  219. /* Handle incoming messages */
  220. BOOL
  221. handle_fn(struct AppInfo * ai, struct MsgHandler * mh, struct TagItem * tl)
  222. {
  223.     struct MHObject *mho = &(mh->mh_Header);
  224.     struct FNInfo  *fni = (struct FNInfo *) mho->mho_SysData;
  225.     struct MsgPort *ClientPort = fni->fni_clientport;
  226.     struct SIPCMessage *sipcmsg;
  227.     struct FNData  *fwd_fndata;
  228.     struct TagItem  tg[3];
  229.     ULONG           FuncID;
  230.  
  231.     while (sipcmsg = (struct SIPCMessage *) GetMsg(ClientPort)) {
  232.     FuncID = sipcmsg->sipc_Type;
  233.  
  234.     if ((FuncID != NO_FUNCTION) && (mho->mho_Status & MHS_OPEN) && (mho->mho_Status & MHS_ENABLED)) {
  235.         fwd_fndata = fni->fni_fndata;
  236.         CopyMem(sipcmsg->sipc_Data, fwd_fndata, sizeof(struct FNData));
  237.  
  238.         /* Make fn taglist, pass tl for consistency */
  239.         tg[0].ti_Tag = APSH_CmdData;
  240.         tg[0].ti_Data = (ULONG) fwd_fndata;
  241.         tg[1].ti_Tag = APSH_CmdDataLength;
  242.         tg[1].ti_Data = sizeof(struct FNData);
  243.         tg[2].ti_Tag = TAG_MORE;
  244.         tg[2].ti_Data = (ULONG) tl;
  245.  
  246.             /* Call the function */
  247.         PerfFunc(ai, FuncID, NULL, tg);
  248.     }
  249.     ReplyMsg((struct Message *) sipcmsg);
  250.     }
  251.     return (TRUE);
  252. }
  253.  
  254. /* Shutdown process, free all allocations */
  255. BOOL
  256. shutdown_fn(struct AppInfo * ai, struct MsgHandler * mh, struct TagItem * tl)
  257. {
  258.     struct MHObject *mho;
  259.     struct FNInfo  *fni;
  260.     struct SIPCMessage *sipcmsg;
  261.  
  262.     if (mh) {
  263.     mho = &(mh->mh_Header);
  264.     fni = mho->mho_SysData;
  265.  
  266.     /* Inform the process it's time to leave. */
  267.     sipcmsg = fni->fni_sipcmsg;
  268.     sipcmsg->sipc_Msg.mn_Node.ln_Type = NT_MESSAGE;
  269.     sipcmsg->sipc_Msg.mn_Length = sizeof(struct SIPCMessage);
  270.     sipcmsg->sipc_Msg.mn_ReplyPort = fni->fni_replyport;
  271.     sipcmsg->sipc_Type = FN_SHUTDOWN;
  272.     PutMsg((struct MsgPort *) fni->fni_fnport, (struct Message *) sipcmsg);
  273.  
  274.     WaitPort((struct MsgPort *) (fni->fni_replyport));
  275.     while (GetMsg(fni->fni_replyport));
  276.  
  277.     DeletePort(fni->fni_replyport);
  278.     DeletePort(fni->fni_clientport);
  279.     Remove((struct Node *) mh);
  280.     FreeVec(mh);
  281.     }
  282.     return (TRUE);
  283. }
  284.  
  285.  
  286. /****** fn_handler/NOTIFY *********************************************
  287. *
  288. *   NAME
  289. *    NOTIFY - Send a command to the fn_handler
  290. *
  291. *   SYNOPSIS
  292. *    FNotifyID   <Command> <FILE=filename> [INT=interval]
  293. *                    [RET=retries] [FLAGS=flags]
  294. *
  295. *   FUNCTION
  296. *    Allows command line commands to be directly send to the handler.
  297. *    
  298. *    Accepted commands: ADD, DEL, SYNC.
  299. *    See fn_handler.h for valid flags.
  300. *    If optional arguments are ommited, interval defaults to 60,
  301. *    retries to -1, flags to FN_NEWER.
  302. *
  303. *   EXAMPLE
  304. *
  305. *    NOTIFY ADD FILE=topcat:mbox INT=20 RET=-1 FLAGS=FN_NEWER|FN_MUSTEXIST
  306. *
  307. *
  308. *   SEE ALSO
  309. *    FileNotify() / fn_handler.h
  310. *
  311. ***********************************************************************
  312. */
  313.  
  314. VOID
  315. FileNotifyA(struct AppInfo * ai, STRPTR str, struct TagItem * tl)
  316. {
  317.     struct MsgHandler *mh;
  318.     struct MHObject *mho;
  319.     struct FNInfo  *fni;
  320.     struct TagItem *fti;
  321.     struct SIPCMessage *sipcmsg;
  322.     struct FNData  *fndata;
  323.     struct FNData  *userbuffer = NULL;
  324.     STRPTR          argv[MAXARG];
  325.     ULONG           argc;
  326.     STRPTR          parsedline;
  327.     STRPTR          tmpptr;
  328.     BOOL           *usererror = NULL;
  329.  
  330.     if (mh = HandlerData(ai, APSH_Handler, "FN", TAG_DONE)) {
  331.     mho = &(mh->mh_Header);
  332.     fni = mho->mho_SysData;
  333.     sipcmsg = fni->fni_sipcmsg;
  334.     fndata = fni->fni_fndata;
  335.     fndata->fnd_Flags = 0;
  336.  
  337.     parsedline = BuildParseLine(str, &argc, argv);
  338.  
  339.     /* Always gets at least the function nameid string passed */
  340.     if (argc >= 2) {
  341.         if (QStrCmpI(argv[1], "ADD"))
  342.         sipcmsg->sipc_Type = FN_ADDTARGET;
  343.         else if (QStrCmpI(argv[1], "DEL"))
  344.         sipcmsg->sipc_Type = FN_DELTARGET;
  345.         else if (QStrCmpI(argv[1], "SYNC"))
  346.         sipcmsg->sipc_Type = FN_SYNC;
  347.         else
  348.         sipcmsg->sipc_Type = 0;
  349.  
  350.         if (sipcmsg->sipc_Type != 0) {
  351.         tmpptr = FindType(argv, "INT", "60");
  352.         stcd_l(tmpptr, &(fndata->fnd_Interval));
  353.         tmpptr = FindType(argv, "RET", "-1");
  354.         stcd_l(tmpptr, &(fndata->fnd_Retries));
  355.         fndata->fnd_Filename = FindType(argv, "FILE", NULL);
  356.         tmpptr = FindType(argv, "FLAGS", "FN_NEWER");
  357.         if (MatchValue(tmpptr, "FN_MUSTEXIST"))
  358.             fndata->fnd_Flags |= FN_MUSTEXIST;
  359.         if (MatchValue(tmpptr, "FN_CREATED"))
  360.             fndata->fnd_Flags |= FN_CREATED;
  361.         if (MatchValue(tmpptr, "FN_SMALLER"))
  362.             fndata->fnd_Flags |= FN_SMALLER;
  363.         if (MatchValue(tmpptr, "FN_BIGGER"))
  364.             fndata->fnd_Flags |= FN_BIGGER;
  365.         if (MatchValue(tmpptr, "FN_NEWER"))
  366.             fndata->fnd_Flags |= FN_NEWER;
  367.         }
  368.     } else {
  369.         /* No commandline or arexx arguments, check for tags. */
  370.         userbuffer = (struct FNData *) GetTagData(FN_Buffer, NULL, tl);
  371.         fndata->fnd_Retries = (LONG) GetTagData(FN_Retries, -1, tl);
  372.         fndata->fnd_Interval = (LONG) GetTagData(FN_Interval, 60, tl);
  373.         fndata->fnd_Flags = (ULONG) GetTagData(FN_Flags, FN_NEWER, tl);
  374.         fndata->fnd_Filename = (UBYTE *) GetTagData(FN_Filename, NULL, tl);
  375.         sipcmsg->sipc_Type = (LONG) GetTagData(FN_Command, 0L, tl);
  376.         usererror = (BOOL *) GetTagData(FN_Error, NULL, tl);
  377.  
  378.         /*
  379.          * Removes all tags. Individual flags can be set and override
  380.          * FN_Flags tag.
  381.          */
  382.  
  383.         do {
  384.         fti = NextTagItem(&tl);
  385.         if (fti) {
  386.             switch (fti->ti_Tag) {
  387.             case FN_MustExist:
  388.             if ((BOOL) fti->ti_Data)
  389.                 fndata->fnd_Flags |= FN_MUSTEXIST;
  390.             else
  391.                 fndata->fnd_Flags ^= FN_MUSTEXIST;
  392.             break;
  393.             case FN_Created:
  394.             if ((BOOL) fti->ti_Data)
  395.                 fndata->fnd_Flags |= FN_CREATED;
  396.             else
  397.                 fndata->fnd_Flags ^= FN_CREATED;
  398.             break;
  399.             case FN_Deleted:
  400.             if ((BOOL) fti->ti_Data)
  401.                 fndata->fnd_Flags |= FN_DELETED;
  402.             else
  403.                 fndata->fnd_Flags ^= FN_DELETED;
  404.             break;
  405.             case FN_Smaller:
  406.             if ((BOOL) fti->ti_Data)
  407.                 fndata->fnd_Flags |= FN_SMALLER;
  408.             else
  409.                 fndata->fnd_Flags ^= FN_SMALLER;
  410.             break;
  411.             case FN_Bigger:
  412.             if ((BOOL) fti->ti_Data)
  413.                 fndata->fnd_Flags |= FN_BIGGER;
  414.             else
  415.                 fndata->fnd_Flags ^= FN_BIGGER;
  416.             break;
  417.             case FN_Newer:
  418.             if ((BOOL) fti->ti_Data)
  419.                 fndata->fnd_Flags |= FN_NEWER;
  420.             else
  421.                 fndata->fnd_Flags ^= FN_NEWER;
  422.             break;
  423.             }
  424.         }
  425.         } while (fti != TAG_DONE);
  426.     }
  427.  
  428.     ai->ai_Pri_Ret = RETURN_WARN;
  429.     ai->ai_Sec_Ret = RETURN_OK;
  430.  
  431.         /* If arguments were passed, either string or tags, we have
  432.          * them now. Check if they are valid.
  433.          */
  434.     if (sipcmsg->sipc_Type > 0 && sipcmsg->sipc_Type < 5) {
  435.         if (strlen(fndata->fnd_Filename) != 0) {
  436.         if (!(sipcmsg->sipc_Type == FN_ADDTARGET && (fndata->fnd_Flags & FN_ALLFLAGS) == 0)) {
  437.             /* Seems we got a valid set of arguments.
  438.                      * Make a message and send to the notify process.
  439.                      */
  440.             sipcmsg->sipc_Msg.mn_Node.ln_Type = NT_MESSAGE;
  441.             sipcmsg->sipc_Msg.mn_Length = sizeof(struct SIPCMessage);
  442.             sipcmsg->sipc_Msg.mn_ReplyPort = fni->fni_replyport;
  443.                     /* Pass it a pointer to the relevant data */
  444.             sipcmsg->sipc_Data = (APTR) fndata;
  445.             PutMsg((struct MsgPort *) fni->fni_fnport, (struct Message *) sipcmsg);
  446.             WaitPort((struct MsgPort *) fni->fni_replyport);
  447.             while (GetMsg(fni->fni_replyport));
  448.  
  449.                     /* Copy the return values from the notify process,
  450.                      * the dispatcher will deal with them.
  451.                      */
  452.             ai->ai_Pri_Ret = sipcmsg->sipc_Pri_Ret;
  453.             ai->ai_Sec_Ret = sipcmsg->sipc_Sec_Ret;
  454.             ai->ai_TextRtn = FN_ErrorMsgs[sipcmsg->sipc_Sec_Ret];
  455.  
  456.             if (ai->ai_Pri_Ret == RETURN_OK) {
  457.             /*
  458.              * If desired, return arguments in application
  459.              * supplied buffer
  460.              */
  461.             if (userbuffer) {
  462.                 CopyMem(sipcmsg->sipc_Data, userbuffer, sizeof(struct FNData));
  463.                 /* Give back own ptr to targetname, not ours */
  464.                 userbuffer->fnd_Filename = fndata->fnd_Filename;
  465.             }
  466.             }
  467.         } else { /* No flags were set */
  468.             ai->ai_Sec_Ret = FN_FLAGS_ERR;
  469.             ai->ai_TextRtn = PrepText(ai, APSH_FN_ID, ai->ai_Sec_Ret, NULL);
  470.         }
  471.         } else { /* No targetname was given */
  472.         ai->ai_Sec_Ret = FN_FILENAME_ERR;
  473.         ai->ai_TextRtn = PrepText(ai, APSH_FN_ID, ai->ai_Sec_Ret, NULL);
  474.         }
  475.     } else { /* No handler command found */
  476.         ai->ai_Sec_Ret = FN_COMMAND_ERR;
  477.         ai->ai_TextRtn = ai->ai_TextRtn = PrepText(ai, APSH_FN_ID, ai->ai_Sec_Ret, NULL);
  478.     }
  479.     if (str)
  480.         FreeParseLine(parsedline);
  481.     } else { /* The handler data could not be found */
  482.     ai->ai_Pri_Ret = RETURN_FAIL;
  483.     ai->ai_Sec_Ret = FN_HANDLER_ERR;
  484.     ai->ai_TextRtn = PrepText(ai, APSH_FN_ID, ai->ai_Sec_Ret, NULL);
  485.     }
  486.     if (usererror) /* Return the error to the appliction, if desired */
  487.     *usererror = ai->ai_Pri_Ret;
  488. }
  489.  
  490. /* The notify process */
  491. void            __saveds
  492. FileNotifier(void)
  493. {
  494.     struct PoolHeader *ph;
  495.  
  496.     struct MsgPort *fnport;
  497.     struct MsgPort *clientport;
  498.     struct MsgPort *timerport;
  499.     struct MsgPort *dosport;
  500.  
  501.     struct timerequest *tr;
  502.     struct SIPCMessage *msg;
  503.     struct SIPCMessage *finalmsg;
  504.     struct StartUpMessage *startupmsg;
  505.     struct Message *timermsg;
  506.  
  507.     struct FNData  *fndata;
  508.  
  509.     struct MinList *hitlist;
  510.     struct TargetNode *tnode, *wnode, *nnode;
  511.     struct FileInfoBlock *fib;
  512.     LONG            lock;
  513.     BOOL            ABORT = FALSE;
  514.     long            pri_error, sec_error, result;
  515.     BOOL            FAILED = TRUE;
  516.     ULONG           client_sig, timer_sig, signal;
  517.  
  518.     /* Chi sono? */
  519.     dosport = &(((struct Process *) FindTask(NULL))->pr_MsgPort);
  520.     WaitPort(dosport);
  521.     startupmsg = (struct StartUpMessage *) GetMsg(dosport);
  522.  
  523.     if (fnport = (struct MsgPort *) CreatePort(0, 0)) {
  524.     if (timerport = (struct MsgPort *) CreatePort(0, 0)) {
  525.         if (ph = (struct PoolHeader *) CreatePrivatePool(MEMF_CLEAR | MEMF_PUBLIC, 4096, 0)) {
  526.         fib = (struct FileInfoBlock *) AllocPooled(sizeof(struct FileInfoBlock), ph);
  527.         tr = (struct timerequest *) AllocPooled(sizeof(struct timerequest), ph);
  528.         hitlist = (struct MinList *) AllocPooled(sizeof(struct MinList), ph);
  529.         NewList((struct List *) hitlist);
  530.         if (!(OpenDevice(TIMERNAME, UNIT_MICROHZ, (struct IORequest *) tr, 0))) {
  531.  
  532.             /* Get client port address & return my port */
  533.             clientport = (struct MsgPort *) startupmsg->su_Port;
  534.             startupmsg->su_Error = 0L;
  535.             startupmsg->su_Port = fnport;
  536.             ReplyMsg((struct Message *) startupmsg);
  537.             FAILED = FALSE;
  538.             client_sig = 1L << fnport->mp_SigBit;
  539.             timer_sig = 1L << timerport->mp_SigBit;
  540.  
  541.             for (;;) {
  542.             signal = Wait(client_sig | timer_sig);
  543.  
  544.             /* C L I E N T  S I G N A L */
  545.  
  546.             if (signal & client_sig) {
  547.                 while (msg = (struct SIPCMessage *) GetMsg(fnport)) {
  548.                 fndata = (struct FNData *) msg->sipc_Data;
  549.                                 /* Start out being OK */
  550.                 msg->sipc_Pri_Ret = RETURN_OK;
  551.                 msg->sipc_Sec_Ret = RETURN_OK;
  552.  
  553.                 switch (msg->sipc_Type) {
  554.  
  555.                 case FN_ADDTARGET:
  556.  
  557.                     /*
  558.                      * Don't allow duplicate targetfiles no
  559.                      * more
  560.                      */
  561.                     if (tnode = FindTarget(hitlist, fndata->fnd_Filename)) {
  562.                     msg->sipc_Pri_Ret = RETURN_WARN;
  563.                     msg->sipc_Sec_Ret = FN_HASNOTIFICATION_ERR;
  564.                     } else {
  565.                     lock = Lock(fndata->fnd_Filename, ACCESS_READ);
  566.                     if (lock == NULL) { /* File doesn't exist */
  567.                         if (fndata->fnd_Flags & FN_MUSTEXIST) {
  568.                         msg->sipc_Pri_Ret = RETURN_WARN;
  569.                         msg->sipc_Sec_Ret = FN_DOESNOTEXIST_ERR;
  570.                         } else
  571.                         fib->fib_Size = 0;
  572.                     } else {
  573.                         /* this is more serious */
  574.                         if (!(Examine(lock, fib))) {
  575.                         msg->sipc_Pri_Ret = RETURN_ERROR;
  576.                         msg->sipc_Sec_Ret = FN_READ_ERR;
  577.                         } else {
  578.                         if (fib->fib_DirEntryType > 0) {
  579.                             msg->sipc_Pri_Ret = RETURN_WARN;
  580.                             msg->sipc_Sec_Ret = FN_NOTFILE_ERR;
  581.                         }
  582.                         UnLock(lock);
  583.                         }
  584.                     }
  585.                     }
  586.                     if (msg->sipc_Pri_Ret == RETURN_OK) {
  587.                     if (tnode = AllocNodeMem(fndata->fnd_Filename, ph)) {
  588.                         *(tnode->fntr) = *tr;
  589.                         tnode->fntr->tr_node.io_Command = TR_ADDREQUEST;
  590.                         tnode->fntr->tr_node.io_Message.mn_ReplyPort = timerport;
  591.                         tnode->fntr->tr_node.io_Message.mn_Node.ln_Pri = 0;
  592.                         tnode->fntr->tr_node.io_Message.mn_Node.ln_Name = NULL;
  593.                         tnode->ntfymsg = NULL;
  594.                         strcpy(tnode->fndata->fnd_Filename, fndata->fnd_Filename);
  595.                         tnode->fndata->fnd_Interval = fndata->fnd_Interval;
  596.                         tnode->fndata->fnd_Retries = fndata->fnd_Retries;
  597.                         tnode->fndata->fnd_Flags = fndata->fnd_Flags;
  598.                         tnode->FileSize = fib->fib_Size;
  599.                         if (tnode->FileSize != 0)
  600.                         CopyMem(&(fib->fib_Date), &(tnode->datestamp), sizeof(struct DateStamp));
  601.                         AddTail((struct List *) hitlist, (struct Node *) tnode);
  602.                         tnode->fntr->tr_time.tv_secs = tnode->fndata->fnd_Interval;
  603.                         tnode->fntr->tr_time.tv_micro = 0;
  604.                         SendIO((struct IORequest *) tnode->fntr);
  605.                     } else {
  606.                         msg->sipc_Pri_Ret = RETURN_ERROR;
  607.                         msg->sipc_Sec_Ret = FN_NOMEM_ERR;
  608.                     }
  609.                     }
  610.                     break;
  611.  
  612.                 case FN_DELTARGET:
  613.                     if (tnode = (struct TargetNode *) FindTarget(hitlist, fndata->fnd_Filename)) {
  614.                     if (!(CheckIO((struct IORequest *) tnode->fntr))) {
  615.                         AbortIO((struct IORequest *) tnode->fntr);
  616.                         WaitIO((struct IORequest *) tnode->fntr);
  617.                     }
  618.                     FreeNodeMem(tnode, ph);
  619.                     msg->sipc_Pri_Ret = 0;
  620.                     } else {
  621.                     msg->sipc_Pri_Ret = RETURN_WARN;
  622.                     msg->sipc_Sec_Ret = FN_UNKNOWN_ERR;
  623.                     }
  624.                     break;
  625.  
  626.                 case FN_INQUIRY:
  627.                     if (tnode = (struct TargetNode *) FindTarget(hitlist, fndata->fnd_Filename)) {
  628.                     msg->sipc_Data = tnode->fndata;
  629.                     } else {
  630.                     msg->sipc_Pri_Ret = RETURN_WARN;
  631.                     msg->sipc_Sec_Ret = FN_UNKNOWN_ERR;
  632.                     }
  633.                     break;
  634.  
  635.                 case FN_SHUTDOWN:
  636.                     wnode = (struct TargetNode *) hitlist->mlh_Head;
  637.                     while (nnode = (struct TargetNode *) (wnode->tnm_Node.mln_Succ)) {
  638.                     if (!(CheckIO((struct IORequest *) wnode->fntr))) {
  639.                         AbortIO((struct IORequest *) wnode->fntr);
  640.                         WaitIO((struct IORequest *) wnode->fntr);
  641.                     }
  642.                     FreeNodeMem(wnode, ph);
  643.                     wnode = nnode;
  644.                     }
  645.                     ABORT = TRUE;
  646.                     finalmsg = msg;
  647.                     break;
  648.  
  649.                 case FN_SYNC:
  650.                     if (tnode = (struct TargetNode *) FindTarget(hitlist, fndata->fnd_Filename)) {
  651.                     if (!(CheckIO((struct IORequest *) tnode->fntr))) {
  652.                         AbortIO((struct IORequest *) tnode->fntr);
  653.                         WaitIO((struct IORequest *) tnode->fntr);
  654.                     }
  655.                     tnode->fntr->tr_time.tv_secs = 0;
  656.                     tnode->fntr->tr_time.tv_micro = 0;
  657.                     SendIO((struct IORequest *) tnode->fntr);
  658.                     } else {
  659.                     msg->sipc_Pri_Ret = RETURN_WARN;
  660.                     msg->sipc_Sec_Ret = FN_UNKNOWN_ERR;
  661.                     }
  662.                     break;
  663.  
  664.                 case FN_NOTIFICATION:
  665.                     /* Meglio tardi che mai! */
  666.                     if (tnode = (struct TargetNode *) FindTarget(hitlist, fndata->fnd_Filename)) {
  667.                     if (fndata->fnd_Status & FN_DONE) {
  668.                         FreeNodeMem(tnode, ph);
  669.                     } else {
  670.                         if (lock = Lock(tnode->fndata->fnd_Filename, ACCESS_READ)) {
  671.                         if (Examine(lock, fib)) {
  672.                             tnode->FileSize = fib->fib_Size;
  673.                         }
  674.                         UnLock(lock);
  675.                         }
  676.                         tnode->fntr->tr_time.tv_secs = tnode->fndata->fnd_Interval;
  677.                         tnode->fntr->tr_time.tv_micro = 0;
  678.                         SendIO((struct IORequest *) tnode->fntr);
  679.                     }
  680.                     }
  681.                     break;
  682.                 }
  683.                 if (msg->sipc_Msg.mn_Node.ln_Type != NT_REPLYMSG && ABORT == FALSE)
  684.                     ReplyMsg((struct Message *) msg);
  685.                 }
  686.             }
  687.             /* T I M E R  S I G N A L */
  688.  
  689.             if (signal & timer_sig) {
  690.                 while (timermsg = (struct Message *) GetMsg(timerport)) {
  691.                 for (tnode = (struct TargetNode *) hitlist->mlh_Head; tnode->tnm_Node.mln_Succ; tnode = (struct TargetNode *) tnode->tnm_Node.mln_Succ) {
  692.                     if (tnode->fntr == (struct timerequest *) timermsg) {
  693.                     break;
  694.                     }
  695.                 }
  696.                 if (tnode->fntr == (struct timerequest *) timermsg) {
  697.                     pri_error = sec_error = RETURN_OK;
  698.                     result = fib->fib_Size = 0;
  699.                     if (tnode->fndata->fnd_Retries > 0)
  700.                     tnode->fndata->fnd_Retries--;
  701.                     if (tnode->fndata->fnd_Retries == 0)
  702.                     result |= FN_DONE;
  703.                     if (lock = Lock(tnode->fndata->fnd_Filename, ACCESS_READ)) {
  704.                     if (!(Examine(lock, fib))) {
  705.                         pri_error = RETURN_ERROR;
  706.                         sec_error = FN_READ_ERR;
  707.                     }
  708.                     UnLock(lock);
  709.                     }
  710.                     if (pri_error == RETURN_OK) {
  711.                     if (!(lock)) {
  712.                         if (tnode->fndata->fnd_Flags & FN_DELETED && tnode->FileSize > 0)
  713.                         result |= FN_DELETED;
  714.                         if (tnode->fndata->fnd_Flags & FN_SMALLER && tnode->FileSize > 0)
  715.                         result |= FN_SMALLER;
  716.                     } else {
  717.                         if (tnode->fndata->fnd_Flags & FN_CREATED && tnode->FileSize == 0)
  718.                         result |= FN_CREATED;
  719.                         if (tnode->fndata->fnd_Flags & FN_NEWER && tnode->FileSize == 0)
  720.                         result |= FN_NEWER;
  721.                         if (tnode->fndata->fnd_Flags & FN_SMALLER && fib->fib_Size < tnode->FileSize)
  722.                         result |= FN_SMALLER;
  723.                         if (tnode->fndata->fnd_Flags & FN_BIGGER && fib->fib_Size > tnode->FileSize)
  724.                         result |= FN_BIGGER;
  725.                         if (tnode->fndata->fnd_Flags & FN_NEWER && tnode->FileSize != 0) {
  726.                         if (CompareDates(&(tnode->datestamp), &(fib->fib_Date)))
  727.                             result |= FN_NEWER;
  728.                         }
  729.                     }
  730.  
  731.                     tnode->FileSize = fib->fib_Size;
  732.  
  733.                     if (result != 0 || pri_error != RETURN_OK) {
  734.                         /* OK, it's a go. */
  735.                         tnode->fndata->fnd_Status = result;
  736.                         tnode->ntfymsg = (struct SIPCMessage *) AllocPooled(sizeof(struct SIPCMessage), ph);
  737.                         if (tnode->FileSize != 0)
  738.                         CopyMem(&(fib->fib_Date), &(tnode->datestamp), sizeof(struct DateStamp));
  739.                         tnode->ntfymsg->sipc_Msg.mn_Node.ln_Type = NT_MESSAGE;
  740.                         tnode->ntfymsg->sipc_Msg.mn_Length = sizeof(struct SIPCMessage);
  741.                         tnode->ntfymsg->sipc_Msg.mn_ReplyPort = fnport;
  742.                         tnode->ntfymsg->sipc_Type = FN_NOTIFICATION;
  743.                         tnode->ntfymsg->sipc_Data = tnode->fndata;
  744.                         tnode->ntfymsg->sipc_DSize = sizeof(struct FNData) + strlen(tnode->fndata->fnd_Filename) + 1;
  745.                         tnode->ntfymsg->sipc_Pri_Ret = pri_error;
  746.                         tnode->ntfymsg->sipc_Sec_Ret = sec_error;
  747.                         PutMsg((struct MsgPort *) clientport, (struct Message *) tnode->ntfymsg);
  748.                     } else {
  749.                         tnode->fntr->tr_time.tv_secs = tnode->fndata->fnd_Interval;
  750.                         tnode->fntr->tr_time.tv_micro = 0;
  751.                         SendIO((struct IORequest *) tnode->fntr);
  752.                     }
  753.                     }
  754.                 }
  755.                 }
  756.             }
  757.             if (ABORT)
  758.                 break;
  759.             }
  760.             CloseDevice((struct IORequest *) tr);
  761.         }
  762.         FreePooled(hitlist, ph);
  763.         FreePooled(tr, ph);
  764.         FreePooled(fib, ph);
  765.  
  766.         DeletePrivatePool(ph);
  767.         }
  768.         DeletePort(timerport);
  769.     }
  770.     DeletePort(fnport);
  771.     }
  772.     Forbid();
  773.  
  774.     if (FAILED) {
  775.     startupmsg->su_Error = RETURN_FAIL;
  776.     startupmsg->su_Port = NULL;
  777.     ReplyMsg((struct Message *) startupmsg);
  778.     } else {
  779.     ReplyMsg((struct Message *) finalmsg);
  780.     }
  781. }
  782.  
  783.  
  784. struct TargetNode *
  785. FindTarget(struct MinList * list, UBYTE * name)
  786. {
  787.     struct TargetNode *node;
  788.  
  789.     for (node = (struct TargetNode *) list->mlh_Head; node->tnm_Node.mln_Succ; node = (struct TargetNode *) node->tnm_Node.mln_Succ) {
  790.     if (strcmp(name, node->fndata->fnd_Filename) == 0)
  791.         return (node);
  792.     }
  793.     return (NULL);
  794. }
  795.  
  796.  
  797. struct TargetNode *
  798. AllocNodeMem(UBYTE * filename, struct PoolHeader * ph)
  799. {
  800.     struct TargetNode *node;
  801.  
  802.     if (node = (struct TargetNode *) AllocPooled(sizeof(struct TargetNode), ph)) {
  803.     if (node->fntr = (struct timerequest *) AllocPooled(sizeof(struct timerequest), ph)) {
  804.         if (node->fndata = (struct FNData *) AllocPooled(sizeof(struct FNData), ph)) {
  805.         if (!(node->fndata->fnd_Filename = (UBYTE *) AllocPooled(strlen(filename) + 1, ph))) {
  806.             FreePooled(node->fndata, ph);
  807.             FreePooled(node->fntr, ph);
  808.             FreePooled(node, ph);
  809.             node = NULL;
  810.         }
  811.         } else {
  812.         FreePooled(node->fntr, ph);
  813.         FreePooled(node, ph);
  814.         node = NULL;
  815.         }
  816.     } else {
  817.         FreePooled(node, ph);
  818.         node = NULL;
  819.     }
  820.     }
  821.     return (node);
  822. }
  823.  
  824.  
  825. void
  826. FreeNodeMem(struct TargetNode * node, struct PoolHeader * ph)
  827. {
  828.     FreePooled(node->fndata->fnd_Filename, ph);
  829.     FreePooled(node->fndata, ph);
  830.     FreePooled(node->fntr, ph);
  831.     if (node->ntfymsg) {
  832.     FreePooled(node->ntfymsg, ph);
  833.     }
  834.     Remove((struct Node *) node);
  835.     FreePooled(node, ph);
  836. }
  837.  
  838.  
  839.  
  840. /* stack to tag */
  841.  
  842. struct MsgHandler *
  843. setup_fn(struct AppInfo * ai, ULONG tags,...)
  844. {
  845.     return (setup_fnA(ai, (struct TagItem *) & tags));
  846. }
  847.  
  848. /****** fn_handler/FileNotify *****************************************
  849. *
  850. *   NAME
  851. *    FileNotify - Send command to fn_handler
  852. *
  853. *   SYNOPSIS
  854. *    FileNotify(struct AppInfo * ai, STRPTR str, ULONG tags,...)
  855. *
  856. *    struct AppInfo *ai;
  857. *    STRPTR str;
  858. *    ULONG tags,...
  859. *
  860. *   FUNCTION
  861. *    This function lets the application send commands to the fn_handler.
  862. *
  863. *   EXAMPLE
  864. *    FileNotify(ai, NULL,
  865. *        FN_Command, FN_INQUIRY,
  866. *        FN_Filename, "dh0:testfile"
  867. *        FN_Error, &error,
  868. *        FN_Buffer, fndata,
  869. *        TAG_DONE);
  870. *
  871. *   INPUTS
  872. *    ai    - pointer to the AppInfo structure for this application.
  873. *    str    - pointer to a command line like string or NULL
  874. *    tags    - stack based TagItems.
  875. *
  876. *
  877. *   RESULT
  878. *    Error values are returned in ai->Pri_Err and ai->Sec_Err.
  879. *    If requested, the primary error value is returned in an 
  880. *    application supplied BOOL variable.
  881. *    If requested, the data as used by the fn_handler is returned
  882. *    in an application supplied FNData structure.
  883. *
  884. *   SEE ALSO
  885. *    NOTIFY / fn_handler.h
  886. *
  887. ***********************************************************************
  888. */
  889.  
  890. VOID
  891. FileNotify(struct AppInfo * ai, STRPTR str, ULONG tags,...)
  892. {
  893.     PerfFunc(ai, FNotifyID, str, (struct TagItem *) & tags);
  894. }
  895.  
  896. struct Process *__stdargs
  897. CreateAProcess(ULONG firsttag,...)
  898. {
  899.     return (CreateNewProc((struct TagItem *) & firsttag));
  900. }
  901.