/* DoSomething.c v1.0 -- a program that undertakes a certain action when
 * a file notify event occurs.
 *
 * Code by Maarten C. ter Mors, July 1996
 */


#include <exec/types.h>
#include <exec/ports.h>
#include <exec/memory.h>
#include <dos/notify.h>

#include <proto/all.h>

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


/// Defines
#define NUMARGS     3
#define ERRHEADER   "DoSomething error"
#define CFGERROR    "Configuration file error"

#define TEMPLATE    "FILES/M,ACTION/K,CONFIG/K"

#define ARG_FILES   0
#define ARG_ACTION  1
#define ARG_CONFIG  2

#define ACTIONPOOLPUDDLESIZE    2048
#define REQUESTPOOLPUDDLESIZE   4096
///


/// Global variables
struct MsgPort *NotifyPort;
void *ActionPool,*RequestPool;
///



BOOL ParseArgs(UBYTE **Files, UBYTE *Action)
/// translates the arguments into notify requests
{
    UBYTE *ActionStr,*FileStr;
    struct NotifyRequest *nreq;
    ULONG i=0,actionlen,filestrlen,notifylen;
    BOOL success=FALSE;

    if (! (Files && Action)) return(FALSE);
    notifylen=sizeof(struct NotifyRequest);

    ActionStr=(UBYTE *)
        AllocPooled(ActionPool,actionlen=(strlen(Action) + 1));
    if (! ActionStr)
        return(FALSE);

    sprintf(ActionStr,"%s",Action);

    while (Files[i]) {
        FileStr=(UBYTE *)
            AllocPooled(RequestPool,filestrlen=(strlen(Files[i]) + 1));
        nreq   =(struct NotifyRequest *)
            AllocPooled(RequestPool,notifylen);

        if (! (FileStr && nreq)) {
            if (FileStr) FreePooled(RequestPool,FileStr,filestrlen);
            if (nreq)    FreePooled(RequestPool,nreq,notifylen);
            break;
        }


        strcpy(FileStr,Files[i]);
        nreq->nr_Name    = FileStr;
        nreq->nr_UserData= (ULONG) ActionStr;
        nreq->nr_Flags   = NRF_SEND_MESSAGE;
        nreq->nr_stuff.nr_Msg.nr_Port= NotifyPort;

        success= StartNotify(nreq) ? TRUE : success;
        i++;
    }

    return(success);
}
///

int main(void)
/// The program entry point, uses ReadArgs() to parse input and starts notify
{
    LONG Arguments[NUMARGS],ConfigArgs[NUMARGS],signal=0L,i;
    struct RDArgs *Args=NULL,*check,ConfigRDArgs;
    BPTR ConfigFile=0L;
    int retcode=0;
    BOOL success=FALSE;
    UBYTE ConfigLine[256],*ExecuteString,SystemString[512];
    struct NotifyMessage *NotifyMsg;


    for (i=0; i<NUMARGS; i++) Arguments[i]=ConfigArgs[i]=0L;
    Args= ReadArgs(TEMPLATE,Arguments,NULL);
    if (! Args) {
        PrintFault(IoErr(),ERRHEADER);
        retcode=10;
        goto end;
    }

    // Allocate memory pools
    ActionPool= CreatePool(MEMF_ANY|MEMF_CLEAR,ACTIONPOOLPUDDLESIZE,ACTIONPOOLPUDDLESIZE);
    RequestPool=CreatePool(MEMF_ANY|MEMF_CLEAR,REQUESTPOOLPUDDLESIZE,REQUESTPOOLPUDDLESIZE);
    if (! (ActionPool && RequestPool)) {
        Printf("%s Can't allocate memory pools !\n",ERRHEADER);
        retcode=20;
        goto end;
    }

    // Allocate message port
    NotifyPort=CreateMsgPort();
    if (! NotifyPort) {
        Printf("%s Can't open notify message port !\n",ERRHEADER);
        retcode=20;
        goto end;
    }


    // Distinguish between normal arguments and config file
    if (Arguments[ARG_CONFIG]) {
        ConfigFile=Open((UBYTE *) Arguments[ARG_CONFIG],MODE_OLDFILE);
        if (! ConfigFile) {
            PrintFault(IoErr(),CFGERROR);
            goto end;
        }

        while(FGets(ConfigFile,ConfigLine,255)) {
            ConfigRDArgs.RDA_Source.CS_Buffer=ConfigLine;
            ConfigRDArgs.RDA_Source.CS_Length=255;
            ConfigRDArgs.RDA_Source.CS_CurChr=0;

            ConfigRDArgs.RDA_DAList=0L;
            ConfigRDArgs.RDA_Buffer=NULL;
            ConfigRDArgs.RDA_ExtHelp=NULL;
            ConfigRDArgs.RDA_Flags=RDAF_NOPROMPT;

            check=ReadArgs(TEMPLATE,ConfigArgs,&ConfigRDArgs);
            if (check) {
                success=
                    ParseArgs((UBYTE **) ConfigArgs[ARG_FILES], (UBYTE *) ConfigArgs[ARG_ACTION])
                    ? TRUE : success;   // if ParseArgs returns TRUE, make success TRUE,
                                        // else leave old value unchanged.
                FreeArgs(check);
            }
        }
        Close(ConfigFile);

    } else
        success= ParseArgs((UBYTE **) Arguments[ARG_FILES], (UBYTE *) Arguments[ARG_ACTION]);

end:
    if (Args) FreeArgs(Args);

    if (success) {
        while(signal != SIGBREAKF_CTRL_C) {
            signal=Wait(1L << NotifyPort->mp_SigBit | SIGBREAKF_CTRL_C);

            NotifyMsg= (struct NotifyMessage *) GetMsg(NotifyPort);
            if (NotifyMsg) {
                ExecuteString= (UBYTE *) NotifyMsg->nm_NReq->nr_UserData;
                if (strstr(ExecuteString,"%s") || strstr(ExecuteString,"%S")) {
                    strcpy(ConfigLine,NotifyMsg->nm_NReq->nr_FullName);
                    AddPart(ConfigLine,NotifyMsg->nm_NReq->nr_Name,512);
                    sprintf(SystemString,ExecuteString,ConfigLine);
                } else
                    strcpy(SystemString,ExecuteString);

                SystemTags(SystemString, TAG_DONE);

                ReplyMsg((struct Message *) NotifyMsg);

            }
        }
    } else
        Printf("%s: Unable to make any notifications.\n",ERRHEADER);


    if (ActionPool) DeletePool(ActionPool);
    if (RequestPool) DeletePool(RequestPool);

    exit(retcode);
}
///

