Solved

VB6 -Access Timed scehduler..

Posted on 2003-11-03
25
619 Views
Last Modified: 2010-04-17
Looking for assistance to write an application in VB 6 with Access 2000 (and/or 97).

The idea is that Access would have at least 2 tables... geo_section_date_time_file_assoc_tbl and the other file_location_tbl (this could be done in 1 table and in more tables - your decide).  The first table would have values entered by Geography, Section, Date, Time and File Id. The second would have File name and Local drive location.  

The idea is to have a program that runs all the time and checks your system time and date. Depending on the time and date, the application would run a file (EXE/WAV/SQF/etc).. that has to be defaulted to certain file, but allow the user to change.. so say I opt in the database to open up Notepad at 7:00PM on June 2 from Section 3 facility in San Diego, CA .. then on such time (PST) on June 2 (every June 2)... Notepad should come up.. reason for Section and Location, is 1 for time (daylight savings or not) and section is say I want to kick off Notepad for Section 3 and MP3 file for Section 2 at the same time... I should be able too.

This app is to run all the time.. System Tray app would be the best. but I leave that to you.
The application should allow user to set the values in the database.. including file and file type... for this maybe a "wndows dialog box to select the file instead of typing in the name and location of the file.

The last and most important thing is that I need to learn from it.. so if you could comment the code.. I would appreciate that.  Also, any references or components added, let me know if comments as well.  Will learn and also use to help class learn.

If the code is tight, I will increase the points.  I have another idea to build on this application, which is to make it an ASP project.. I hope to use the example and build on it with ASP to make it a web application for my class project.

Looking forward to your ideas...

Thanks.


0
Comment
Question by:alibabas
  • 11
  • 10
  • 4
25 Comments
 
LVL 8

Expert Comment

by:SNilsson
Comment Utility
Have you thought about using VB and windows scheduler?
This sound like a job for scheduler.
0
 
LVL 8

Expert Comment

by:SNilsson
Comment Utility
Source code for an example with VB & scheduler:

http://www.programmersheaven.com/zone1/cat605/29396.htm
0
 

Author Comment

by:alibabas
Comment Utility
I went to the site.. but the download requires a password.. which requires me to pay... plus if the owrk is done already... I can't request for the more detailed "commenting" allowing us to learn.

Does Vb have any compnoents that do the schedulers work or can you help me create something like that?  

0
 
LVL 22

Expert Comment

by:cookre
Comment Utility
To create your own, you will need several things.  

Scheduling Requirement Decisions
     1) To what day level do you want to schedule events?  
         Daily?  Day of week?  Specific date?

     2) What time granularity do you want to specify?  
         Do you want to specify exact times?  Time windows?

     3) If an event window is missed, what happens?  
         Run right away?   Wait until next window?

Develop a notation for defining events as required above.

Write interpreter.

---

You'll need an event definition file to identify scheduled events.  Something like an INI file or registry key would be handy.  A section header (or key) would define the event name and values within the section would give the event parameters.  For example:

[EventNameX]
COMMAND=<CommandToRun>


DATE=<DayList>
This specifies the days of the week on which the event is to be executed.  <DayList> is a list of 3-character day name abbreviations separated by commas.  The recognized abbreviations are: SUN, MON, TUE, WED, THU, FRI, SAT.  Day name abbreviations may appear in any order and case is not important.


TIME=<TimeIntervalList>
This specifies one or more time intervals during which the event may be considered for execution (in conjunction with the day(s) specified on the DATE= command).  Time intervals are separated by commas and have the format:
<StartHHMM>-<EndHHMM>
Each HHMM represents a 4-digit hour and minute combination based on a 24-hour clock.
To simplify the specification of events that are to be executed hourly, you may define a single window using '*' for both the beginning and end hour.

Note that there is no requirement that an event be completed within the specified interval.  Rather, the interval is used only to specify a range of acceptable event begin times.

---
 
Next you'll need an event history log that records, at least, the most recent execution of any event.  Something whose lines look like:
<EventName>=<LastExecutionDate as YYYYMMDD><LastExecutionTime as HHMM>

---

At some regular interval, say once every minute:

* Load the event definition info
(opening it each time means changes take effect immediately)

* Look at each event to see if it qualifies for execution now.

* If it does, look in the event history log to see if the execution window it qualified for has been satisfied yet.

---

And that's pretty much it - a simple, not at all fancy event scheduler.
0
 
LVL 8

Expert Comment

by:SNilsson
Comment Utility
Sorry about the password file alibabas, I should have checked.

This one should hopefully work:
http://www.mvps.org/emorcillo/download/cod/schedule.zip

0
 

Author Comment

by:alibabas
Comment Utility
SNilsson - Is it possible to get code for this as the Schedule.zip file has a DLL which I am not allowed to register at my work pc.. which is where I need it.  Is it possible for you to help with the code.. provide snippets or full code?

Cookre -  could you elaborate? I am not sure what you were trying to do.. give direction or solution.. please clarify.. and if you can help with code .. that would be great.
0
 
LVL 22

Expert Comment

by:cookre
Comment Utility
That was a coarse outline for a scheduler I wrote for NetWare servers, but the idea can be implemented on any platform.  Before starting any coding, however, you'll have to fully define WHAT it's supposed to do (the coding is just the HOW).

Recapping from above:

Scheduling Requirement Decisions
     1) To what day level do you want to schedule events?  
         Daily?  Day of week?  Specific date?

    Do you want scheduled events to repeat?  If so, then such events would have start times
    such as MONDAY/23:30, DAILY/16:45, FIRSTOFMONTH/10:00

    Single executions might be defined like 2003/12/25-00:01

    Other event times might be things like the third Tuesday of each month.


     2) What time granularity do you want to specify?  
         Do you want to specify exact times?  Time windows?

     Some events may have to be scheduled for precise times, e.g., 23:56.
     Others may be more lax - anytime between 23:00 and 23:55.


     3) If an event window is missed, what happens?  
         Run right away?   Wait until next window?

     Despite all out desires, it may not be possible for something to start at 15:17.  The box
    may be busy doing something else that has control.  That's the main reason for allowing
    a start window instead of a hard, fixed time.  In either case, however, one needs to specify
   what the scheduler should do if an event window is missed.

Basicly, this means you need to define how you want to define a scheduled event.  Implicit therein is also the question of interface - text file, GUI, whatever.
0
 

Author Comment

by:alibabas
Comment Utility
I have tried to answer all your questions in CAPS.. let me know if I need to clarify anything.
Thanks.

Scheduling Requirement Decisions
     1) To what day level do you want to schedule events?  
         Daily?  Day of week?  Specific date?
         
******   THE PROGRAM NEEDS TO RUN DAILY   ***
         
    Do you want scheduled events to repeat?  If so, then such events would have start times
    such as MONDAY/23:30, DAILY/16:45, FIRSTOFMONTH/10:00

    Single executions might be defined like 2003/12/25-00:01

    Other event times might be things like the third Tuesday of each month.

******         DEPENDING ON THE MONTH (NOT JAN TO FEB, BUT COMPANY PERIODS/MONTHS)... EACH DAY COULD HAVE DIFFERENT NUMBER OF EVENTS PLANNED.  SO MONTH 3 COULD HAVE 6 EVENTS PER DAY, WHILE MONTH 4-7 HAVE 3 EVENTS, AND THE REST 5 EVENTS.
      
      ALSO THE ISSUE IS SINCE WE ARE TRYING TO ALIGN MONTH 1 TO JAN OVER THE NEXT 3-4 YEARS, (THIS IS NOT ACCOUNTING PRACTICE .. JUST TRYING TO MOVE FROM COMPANY ORIGINATION TIME FROM MID YEAR TO BEGINNING OF ROMAN CALENDER.  SO THIS YEAR, MONTH 3 IS JUNE 15 - JULY 14, BUT FOR NEXT YEAR (DEPENDING ON A NUMBER OF DAYS) THE TIME HAS TO BE MOVED BACK.  SO IF I PICK 60 AS THE COUNT, THEN MONTH 3 SHOULD REPRESENT APRIL 15 - MAY 14 (ROUGHLY SPEAKING)... BASICALLY TO REALIGN THE SCHEDULER WITH THE MONTH CHANGES.. THIS WAY MNTH HAS 6 EVENTS (LIKE ABOVE).. BUT IT DOES NOT MATTER THAT THIS YEAR IT WAS FROM JUNE AND NEXT YEAR WILL BE APRIL ( THE DATE DIFFERENCE TIME WILL BE HARDCODED, BUT I WILL NEED TO KNOW WHERE TO CHANGE).  ******  


     2) What time granularity do you want to specify?  
         Do you want to specify exact times?  Time windows?
         
******      EXACT TIMES NEEDED   ******  

     Some events may have to be scheduled for precise times, e.g., 23:56.
     Others may be more lax - anytime between 23:00 and 23:55.


     3) If an event window is missed, what happens?  
         Run right away?   Wait until next window?
         
******      IF MISSED, NO PROBLEM, GO TO NEXT ONE... NOT SURE IF IT IS WORTH GOING TO DATABASE FOR NEXT TIME CHECK OR HOLD VALUE IN XML/TXT FILE. OR FLAG TABLE VALUE.    ******  
                 
     Despite all out desires, it may not be possible for something to start at 15:17.  The box
    may be busy doing something else that has control.  That's the main reason for allowing
    a start window instead of a hard, fixed time.  In either case, however, one needs to specify
   what the scheduler should do if an event window is missed.

Basicly, this means you need to define how you want to define a scheduled event.  Implicit therein is also the question of interface - text file, GUI, whatever.

******     THE GUI SHOULD BE ABLE TO CHECK DATABASE VALUES AND RELATIONSHIPS.. .BUT BE SIMPLE ... AND UPDATE THE SCHEDULER AND TASKS TO PERFORM...  ******  

0
 

Author Comment

by:alibabas
Comment Utility
I will only give points for code...
I am running out of time..
Some take on this task. Thanks.
0
 
LVL 22

Expert Comment

by:cookre
Comment Utility
Sorry for the delay - I got sick and was in the hospital.

Given your time contraints, you should consider an off the shelf package.

I would estimate that writting this would take several weeks  - and that's presuming a conversion of one that I have for NetWare written in Rexx.
0
 

Author Comment

by:alibabas
Comment Utility
Cookre ... no problem...
Hope you are feeling well.
As for of the shelf.. what do you recommend?
Thanks.
0
 

Author Comment

by:alibabas
Comment Utility
Guys... I would prefer customized code.. but will look into the packages if anyknows any good cheap ones.
Thanks.
0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 22

Expert Comment

by:cookre
Comment Utility
If you can read Rexx, I edited down my scheduler to ~800 lines (removed the NetWare specific things).

Interested?
0
 

Author Comment

by:alibabas
Comment Utility
Cookre...
I don't know REXX... however if you think the code is easy to read or can be understood by someone who is a vb/asp programmer and who knows bits of Perl/Smalltalk...
again.. i don't know rexx..but am willing to try it.
thanks
0
 
LVL 22

Expert Comment

by:cookre
Comment Utility
I'll post it tonight (US EST) when I get to the box that has it...
0
 

Author Comment

by:alibabas
Comment Utility
Cookre...
I did not receive the Rexx code... let me know.
thanks.
0
 
LVL 22

Expert Comment

by:cookre
Comment Utility
I do apologize - that and several thing simply disappeared from my pea brain.  Here it is:

(A lot of code onapplicable to this discussion has been removed)

/* Every WaitTime seconds, the program looks at sched.INI and
** processes each group therein.  For each group (command), the
** history file is read to see if its time to execute that command.
** (Commands are identified by the CommandName in the group header.)
**
** If a command is executed, its history record is updated or created.
**
** Each command thats been executed has one history record of the form:
** <CommandName>=<LastExecutionDate as YYYYMMDD><LastExecutionTime as HHMM>
*/
arg CmdParm
parse upper value CmdParm with WorkDir "," OptList
StartDate=date("S")
StartTime=time("N")

SchedVer="4.4"
WaitTime=60       /* Sleep interval in seconds                               */
CR="0d"x
LF="0a"x
/* WorkDir  = "N/A" - now taken from command line */
HistFile = WorkDir || "sched.hst"
IniFile  = WorkDir || "sched.ini"
LocalIni = WorkDir || "sched.ili"
SchedLog = WorkDir || "sched.log"

rc=stream(SchedLog,"c","qe")
if rc\=1 then do
   rc=stream(SchedLog,"c","crw")
   if rc\=0 then do
      msg="Unable to create log file"
      call ShowWait
      exit
      end
   rc=stream(SchedLog,"c","close")
   end
if 0>stream(SchedLog,"c","open") then do
   msg="Unable to open log file"
   call ShowWait
   exit
   end

/*
** Initialize environment variables that won't change during execution
*/
FSN=""
FSN83=""
...snip
ShowSolidarity=0

/*
** Wake up every now and then to see what to do
*/
DidALogin=0
do forever
   drop IniData
   drop ThingToShift
   drop BothInis
   if (ShowSolidarity>ShowTime) then do
      msg="sched v" || SchedVer || " still active from " || WorkDir
      call LogIt
      ShowSolidarity=0
      /* While we're at it, let's keep the logfile size down */
      rc=stream(SchedLog,"c","close")
      rc=stream(SchedLog,"c","open")
      SchedLogSize=lines(SchedLog)
      if SchedLogSize>2000 then do
         /* We check for 2000, but chop to 1000 - this means we're */
         /* constantly chopping little amounts                     */
         ChopPoint=SchedLogSize-1000
         /* Skip over all but the last 1000 lines */
         do i=1 to ChopPoint
            TrashIt=linein(SchedLog)
            end
         RecentSchedLog.0=0
         do i=ChopPoint+1 to SchedLogSize
            idx=i-ChopPoint
            RecentSchedLog.idx=linein(SchedLog)
            RecentSchedLog.0=idx
            end
         /* Recreate SchedLog with the recent 1000 lines */
         rc=stream(SchedLog,"c","close")
         rc=stream(SchedLog,"c","create")
         AttrRec.MFileAttributesMask = -1
         AttrRec.MFileAttributes     = 65536
         rc=ChangeDirectoryEntry(SchedLog,"AttrRec.",2,0)
         do i=1 to RecentSchedLog.0
            call lineout SchedLog,RecentSchedLog.i
            end
         end
      end

   /*
   ** Step through INI file for things to do
   */
   rc=stream(IniFile,"c","open read")
   if rc\=0 then do
      msg="Unable to open " || IniFile
      call LogIt
      rc=pause(WaitTime)
      ShowSolidarity=ShowSolidarity+WaitTime
      iterate
      end
   /*
   ** Load up a copy of the INI file
   */
   IniFileChars=chars(IniFile)
   IniData=charin(IniFile,1,IniFileChars)
   rc=stream(IniFile,"c","close")
   ...snip
   FileSize=IniFileChars
   i=1

   /* Add a plain text CRLF at the end in case the last line didn't have one */
   IniData=IniData||CR||LF
   IniFileChars=IniFileChars+2
   BothInis.0=0
   i=1
   do while i<=IniFileChars
      /* Concatenate non-line terminators into current line */
      BothInis.0=1+BothInis.0
      CurIdx=BothInis.0
      BothInis.CurIdx=""
      CurChar=substr(IniData,i,1)
      do while CurChar\=CR & CurChar\=LF
         BothInis.CurIdx=BothInis.CurIdx || CurChar
         i=i+1
         CurChar=substr(IniData,i,1)
         end
      /* We're at the end of a line */
      do while CurChar=CR | CurChar=LF
         i=i+1
         CurChar=substr(IniData,i,1)
         end
      end
   /*
   ** Now step through our copy of the INI file
   */
   IniFileSize=BothInis.0
   IniEof=0
   IniLineNo=1
   IniLine=translate(BothInis.IniLineNo)
   do while IniEof==0
      /*
      ** Initialize group fields
      */
      CmdName=""
      CmdType=""
      CmdUser=""
      CmdPassword=""
      CmdServer=""
      CmdNLM=""
      CmdDate=""
      CmdTime=""
      CmdFrom=""
      CmdTo=""
      CmdFile=""
      CmdRen=""
      CmdWaitFile=""
      CmdText=""
      CmdRunOnce=""
      CmdCopyNewOnly=""

      call LoadGroup
      call ExecuteGroup
      if DidALogin\=0 then leave
      end

   /*
   ** Wait a bit till next pass
   */
   rc=pause(WaitTime)
   ShowSolidarity=ShowSolidarity+WaitTime
   end
msg="End sched"
call LogIt
exit

/*****************************  LoadGroup  ********************************/
LoadGroup:
/*
** Initialize group fields
** Upon entry, the first line of the group is loaded
*/
call SetENV /* Replace environment vars in IniLine */

CmdName=strip(strip(IniLine,,"["),,"]")
IniLineNo=IniLineNo+1
IniLine=translate(BothInis.IniLineNo)

/*
** Keep scanning til we hit EOF or the next [...] line
*/
do forever
   IniLine=strip(IniLine)
   call SetENV
   /*
   ** Tell the caller we got EOF
   */
   if IniLineNo>IniFileSize then do
      IniEOF=1
      leave
      end
   /*
   ** Check for start of next group
   */
   if substr(IniLine,1,1)=="[" then leave

   /*
   ** Skip blank lines
   */
   if 0==length(IniLine) then do
      IniLineNo=IniLineNo+1
      IniLine=translate(BothInis.IniLineNo)
      iterate
      end

   /*
   ** Skip comment lines
   */
   if left(IniLine,1)==";" then do
      IniLineNo=IniLineNo+1
      IniLine=translate(BothInis.IniLineNo)
      iterate
      end

   /*
   ** Its something to look at
   */
   EqualPos=pos("=",IniLine)
   if 2>EqualPos then do
      /* Ignore bad lines for now */
      IniLineNo=IniLineNo+1
      IniLine=translate(BothInis.IniLineNo)
      iterate
      end
   PartName=left(IniLine,EqualPos-1)
   PartArg=right(IniLine,length(IniLine)-EqualPos)

   /*
   ** Now let's see what we got
   */
   PartName=translate(PartName)
   select
          when PartName="TYPE" then do
               CmdType=PartArg
               end
          when PartName="DATE" then do
               CmdDate=PartArg
               end
          when PartName="TIME" then do
               CmdTime=PartArg
               end
          when PartName="RUNONCE" then do
               CmdRunOnce=PartArg
               end
          when PartName="COPYNEWONLY" then do
               CmdCopyNewOnly=PartArg
               end
          when PartName="CMD" then do
               CmdText=CmdText || PartArg
               end
          when PartName="FROM" then do
               CmdFrom=PartArg
               if right(CmdFrom,1)="\" then do
                  CmdFrom=left(CmdFrom,length(CmdFrom)-1)
                  end
               end
          when PartName="TO" then do
               CmdTo=PartArg
               if right(CmdTo,1)="\" then do
                  CmdTo=left(CmdTo,length(CmdTo)-1)
                  end
               end
          when PartName="FILE" then do
               CmdFile=PartArg
               end
          when PartName="RENAME" then do
               CmdRen=PartArg
               end
          when PartName="WAITFILE" then do
               CmdWaitFile=PartArg
               end
          otherwise do
               msg="Unrecognized line ignored:<" || IniLine || ">"
               call LogIt
               end
          end

   /*
   ** Get next line
   */
   IniLineNo=IniLineNo+1
   IniLine=translate(BothInis.IniLineNo)
   end
return

/**************************  ExecuteGroup  *********************************/
ExecuteGroup:
/*
** See if this event qualifies
*/
if 0=DoWeRunIt() then return

/*
** The event qualifies for execution, now check the HST file for:
** 1) If it's a RUNONCE and in the HST file, don't run it again
** 2) The call to DoWeRunIt leaves the qualified interval in TimeInterval
**    and the qualified day in TODAY.  Look thru the HST file for
**    an entry with the qualified day and interval whose date is today's.
** 3) If the qualified window was a masked hourly on (*xx-*yy), replace
**    the *s in TimeInterval with the current hour.  This will give us
**    something to put in HST to reflect this instance of the event.
**    (If the masked interval were to go in HST, we would only get
**    one execution per day.)
*/
if left(TimeInterval,1)="*" then do
   /* NOW is set in InWindow */
   HH=left(NOW,2)
   TimeInterval=HH || substr(TimeInterval,2,3) || HH || right(TimeInterval,2)
   end
GroupDate=date("I")
EntryFound=0
HistRecs.0=0
rc=stream(HistFile,"c","open")
if rc=0 then do
   HistLen=lines(HistFile)
   if HistLen>0 then do
      /* TARGET is the qualified EventName,DayName,Interval  */
      /* Search for an instance from today while loading HST */
      Target=CmdName||","||TODAY||","||TimeInterval||","||GroupDate
      if CmdRunOnce="YES" then Target=CmdName
      TargetSize=length(Target)
      do HistIdx=1 to HistLen
         HistLine=linein(HistFile)
         HistRecs.HistIdx=HistLine
         CommaPos=pos(",",HistLine)
         if CommaPos=0 then iterate
         if left(HistLine,TargetSize)\=Target then iterate
         EntryFound=1
         end
      HistRecs.0=HistLen
      end
   rc=stream(HistFile,"c","close")
   end

/* If we found our target, don't run it again */
if EntryFound>0 then return

/*
** Looks like we gotta do it
*/
msg="Processing <" || CmdName || ">"
call LogIt

/* Build list of servers, if any, this command is to work with */
if CmdServer\="" & "*"=left(CmdServer,1) then do
   ......
   end
else do
   /* Server= is either empty or not an indirect file */
   ServerList.0=1
   ServerList.1=CmdServer
   end

/* Save the original TO and FROM strings, since environment variable */
/* substitution changes them (not nice if SERVER=*something).        */
HoldCmdTo=CmdTo
HoldCmdFrom=CmdFrom
HoldCmdRen=CmdRen
/* Apply command for each server specified (blank or not) */
do SvrIdx=1 to ServerList.0
   CmdServer=ServerList.SvrIdx
   if length(CmdServer)>1 then do
      rc=DoAttach()
      if rc\=0 then return
      end
   select
          when translate(CmdType)="CONSOLE" then do
               call ExecuteConsoleCmd
               end
          when translate(CmdType)="COPY" then do
               call ExecuteCopyCmd
               CmdTo=HoldCmdTo
               CmdFrom=HoldCmdFrom
               CmdRen=HoldCmdRen
               end
          otherwise do
               msg="Command <" || CmdName || "> has unknown type <" || CmdType || ">"
               call LogIt
               end
          end
   if length(CmdServer)>1 then do
      call ClearRemote
      end
   end
rc=NWDSLogout()

/* Update HST file */
rc=stream(HistFile,"c","create")
if rc\=0 then do
   msg="Unable to re-create " || HistFile
   call LogIt
   return
   end

if HistRecs.0>0 then do
   CmdNameLen=length(CmdName)
   do HistIdx=1 to HistRecs.0
      /* Dont keep old instance of this event, if any.      */
      /* Note that we only need the most recent instance    */
      /* of *xx-*yy events ('cause time don't go backwards) */
      if left(HistRecs.HistIdx,CmdNameLen)=CmdName then iterate
      rc=lineout(HistFile,HistRecs.HistIdx)
      end
   end
NewLine=CmdName||","||TODAY||","||TimeInterval||","||GroupDate
rc=lineout(HistFile,NewLine)
rc=stream(HistFile,"c","close")
return

/*****************************  DoWeRunIt  ********************************/
DoWeRunIt:
/* Return 0 to say not to run event */

if length(CmdDate)<3 then do
   msg="Invalid DATE=<" || CmdDate || "> from event <" || CmdName || ">"
   call LogIt
   return 0
   end

/*
** Look for WaitFiles
*/
if length(CmdWaitFile)>0 then do
   rc=stream(CmdWaitFile,"C","QE")
   if rc\=1 then return 0
   end

/* Get today's abbreviation */
TODAY=translate(left(date("W"),3))

/* See if we run today */
if 0=pos(TODAY,CmdDate) then return 0

/* See if we fall in one of the time windows */
/* First get current time as HHMM            */
NOW=time("N")
NOW=left(NOW,2) || substr(NOW,4,2)

/* Now compare NOW against each window */
TimeWindows=CmdTime
TimeInterval=""
ScanDone=0
parse upper value TimeWindows with TimeInterval "," TimeWindows
if length(TimeWindows)<1 then ScanDone=1
if 0\=InWindow(NOW TimeInterval) then return 1
do while ScanDone=0
   parse upper value TimeWindows with TimeInterval "," TimeWindows
   if length(TimeWindows)<1 then ScanDone=1
   if 0\=InWindow(NOW TimeInterval) then return 1
   end
/* Guess we're not in one of the windows */
return 0

/*************************  InWindow  ****************************/
/* Return 0 if not in window, 1 otherwise                        */
/* First arg is time to check as HHMM                            */
/* Second arg is an interval in the for HHMM-HHMM                */
/* Special case *mm-*mm allows simple hourly specification       */

InWindow:
arg HHMM Interval
HH=left(HHMM,2)
MM=right(HHMM,2)
DashPos=pos("-",Interval)
if DashPos<3 then do
   msg="Invalid TIME=" || CmdTime
   call LogIt
   return 0
   end
if length(Interval)<(DashPos+3) then do
   msg="Bad TIME=" || CmdTime
   call LogIt
   return 0
   end

/* Firm up the interval start */
IntBeg=left(Interval,DashPos-1)
if length(IntBeg)=3 then do
   if left(IntBeg,1)\="*" then do
      msg="Invalid interval start " || IntBeg
      call LogIt
      return 0
      end
   /* This guy is automatically in the current hour */
   IntBeg=HH || right(IntBeg,2)
   end

/* Do the same thing for interval end */
IntEnd=substr(Interval,DashPos+1)
if length(IntEnd)=3 then do
   if left(IntEnd,1)\="*" then do
      msg="Invalid interval end " || IntEnd
      call LogIt
      return 0
      end
   /* This guy is automatically in the current hour */
   IntEnd=HH || right(IntEnd,2)
   end

if IntBeg<=HHMM & HHMM<=IntEnd then return 1
return 0


/*************************  ExecuteConsoleCmd  ****************************/
ExecuteConsoleCmd:

......

return

/**************************  ExecuteCopyCmd  ******************************/
ExecuteCopyCmd:

/* Make sure we have at least one file to copy */
CmdFrom=DynEnv(CmdFrom)
FileMask=CmdFrom||"\"||CmdFile

NumFiles=ListFile(FileMask,"FileList.")
if NumFiles=0 then do
   msg="File(s) not found [" || CmdName || "]: " || FileMask
   call LogIt
   call ClearRemote
   return
   end

/* Make sure destination directory exists */
CmdTo=DynEnv(CmdTo)
PathToVerify=CmdTo

rc=VerifyPath()
if rc\=0 then do
   msg="Copy aborted - unable to create destination (" || rc || ")"
   call LogIt
   call ClearRemote
   return
   end

/* Now we copy each file that matches the mask */
FileIdx=1
do while FileIdx<=NumFiles
   curfile=strip(FileList.FileIdx)
   if length(curfile)>5 then do
      if right(curfile,5)="<DIR>" then do
         FileIdx=FileIdx+1
         iterate
         end
      end
   SourceFile=CmdFrom || "\" || curfile
   DestFile  =CmdTo   || "\" || curfile
   if length(CmdRen)>0 then do
      /* Change destination filename, if needed */
      CmdRen=DynEnv(CmdRen)
      DestFile=CmdTo || "\" || CmdRen
      end
   DestCmd   ="CO "   || DestFile
   /* Handle CopyNewOnly=YES */
   if translate(CmdCopyNewOnly)="YES" & length(CmdRen)=0 then do
      /* Only copy the file if it's newer */
      IsItOne=ListFile(DestFile,"DestList.")
      if IsItOne=1 then do
         /* Save destination date/time stamp */
         DestStamp=right(DestList.1,19)
         /* Get source date/time stamp */
         IsItOne=ListFile(SourceFile,"DestList.")
         if IsItOne=1 then do
            SourceStamp=right(DestList.1,19)
            if SourceStamp<=DestStamp then do
               msg="[" || CmdName || "] " || SourceFile || " not newer, copy skipped"
               call LogIt
               FileIdx=FileIdx+1
               iterate
               end
            end
         end
      end
   /* Finally - we can do the copy */
   rc=stream(SourceFile,"C",DestCmd)

   /* Try up to three times if it failed */
   RetryCount=0
   do while (rc\=0) & (RetryCount<3)
      RetryCount=RetryCount+1
      msg="[" || CmdName || "] failed (" || rc || ") Retry " || RetryCount
      call LogIt
      Dummy=pause(30)
      rc=stream(SourceFile,"C",DestCmd)
      end
   if rc\=0 then do
      msg="[" || CmdName || "] copy aborted (" || SourceFile || " to " || DestFile || ")  (" || rc || ")"
      call LogIt
      call ClearRemote
      return
      end
   msg="[" || CmdName || "] - OK"
   call LogIt
   FileIdx=FileIdx+1
   end

return




/*********************************  LogIt  ********************************/
Logit:
say date()||" "||time()||" "||msg
call lineout SchedLog,date()||" "||time()||" "||msg
return

/*********************************  ShowWait  ********************************/
/* Display a message then wait for a key or until timeout                    */

ShowWait:
DelayCtr=60
say msg
rc=GetCursor("CursorPos.")
do while DelayCtr>0
   rc=SetCursor(CursorPos.row,CursorPos.column)
   say "Press CTRL-C or wait " || DelayCtr || " seconds...    "
   rc=pause(1)
   DelayCtr=DelayCtr-1
   end
return

/******************************* VerifyPath ******************************/
VerifyPath:
/* Create the path in <PathToVerify> if it doesn't exist */

/* Edit locally */
Remainder=PathToVerify

/* Standardize slashes */
Remainder=strip(translate(Remainder,"/","\"))

/* Extract server name */
VerifyServer=translate(left(Remainder,11))

/* Start off by stripping out the drive portion */
parse upper value Remainder with LeftPart ":/" Remainder
PathParts.0=1
PathParts.1=LeftPart || ":"

/* Split out the remaining parts */
do while length(Remainder)\=0
   PathParts.0=1+PathParts.0
   CurrentPart=PathParts.0
   parse upper value Remainder with LeftPart "/" Remainder
   PathParts.CurrentPart=LeftPart
   end

/* Now that we have the parts, find the first missing directory, if any */
/* VerifyPath is called after we've logged into the tree and attached   */
/* to the remote server, if any.  If the destination directory needs    */
/* to be created and it is back on the local server, we have to         */
/* switch back to the local server for the MKDIR to work.               */
DestOnLocal=0
if length(CmdServer)=11 & (VerifyServer\=translate(CmdServer)) then do
   /* We have to temporarily switch back to the local server */
   DestOnLocal=1
   HoldConn=GetCurrentConnection()
   HoldFSID=GetCurrentFileServerID()
   rcl=SetCurrentFileServerID(0)
   rcl=SetCurrentConnection(0)
   end
/* Start one level below the root of the volume */
CurrPath=PathParts.1
if PathParts.0>1 then do
   do idx=2 to PathParts.0
      CurrPath=CurrPath || PathParts.idx
      /* See if this path exists */
      /* We used to create a fixed file name, but found out that           */
      /* Netware doesn't like a bazillion identical names, sooo            */
      /* we create a filename CCCCnnnS.SUU where:                          */
      /*      CCCC is the city code from the server name                   */
      /*       nnn is the right-most three chars from server name          */
      /*       S.SUU are the seconds and miliseconds from the current time */
      /* Although this will still have some collisions, it won't be near   */
      /* as many as with a fixed file name.                                */
      SSDotUU=substr(time("L"),7,5)
      SvrPart=left(VerifyServer,4) || right(VerifyServer,3)
      FileName=SvrPart || left(SSDotUU,1)
      ExtName=substr(SSDotUU,2,1) || right(SSDotUU,2)
      FileName=FileName || "." || ExtName
      FileName=CurrPath || "\" || FileName
      rcl=stream(FileName,"c","create")
      if rcl\=0 then do
         /* Nope, let's make it */
         rcl=stream(CurrPath,"c","mkdir")
         if rcl\=0 then do
            msg="Unable to create <" || CurrPath || ">  (" || rcl || ")"
            call LogIt
            if DestOnLocal=1 then do
               /* Switch back to the remote, if needed */
               rcl=SetCurrentFileServerID(HoldFSID)
               rcl=SetCurrentConnection(HoldConn)
               DestOnLocal=0
               end
            return 1
            end
         end
      /* Close the name so we don't interfere with a later pass */
      rcl=stream(FileName,"c","close")
      rcl=stream(FileName,"c","delete")
      CurrPath=CurrPath || "\"
      end
   end
return 0

/******************************* SetENV ******************************/
SetENV:
/*
** Replace environment variables in IniLine
**
** Recognizes:     FSN - File Server Name
**                 FSN83 - File Server Name in 8.3 format
**
**
** Scan INILine for all instances of known %env% and replace with
** appropriate value.  Note our presumption that INILine has already
** been converted to upper case.
*/

/* Look for FileServerName */
vpos=pos("%FSN%",IniLine)
do while vpos>0
   /* We have a hit, find it's start */
   tpos=pos("%FSN%",IniLine)

   /* Extract whatever is to the left of %FSN% */
   LeftPart=""
   if tpos>1 then LeftPart=left(INILine,tpos-1)

   /* Now extract whatever is to the right of %FSN% */
   RightPart=""
   if tpos<(length(IniLine)-4) then RightPart=right(INILine,1+(length(INILine)-(tpos+5)))

   /* Reconstruct INILine, using value for FSN */
   INILine=Leftpart || FSN || RightPart
   vpos=pos("%FSN%",IniLine)
   end

/* Look for File Server Name in 8.3 format */
vpos=pos("%FSN83%",IniLine)
do while vpos>0
   tpos=pos("%FSN83%",IniLine)
   LeftPart=""
   if tpos>1 then LeftPart=left(INILine,tpos-1)
   RightPart=""
   if tpos<(length(IniLine)-6) then RightPart=right(INILine,1+(length(INILine)-(tpos+7)))
   INILine=Leftpart || FSN83 || RightPart
   vpos=pos("%FSN83%",IniLine)
   end

return

/******************************* DynENV ******************************/
/* Replace dynamic environment variables in input string             */
DynENV:
arg StringIn

/* Replace %*% with remote server name */
vpos=pos("%*%",StringIn)
do while vpos>0
   tpos=pos("%*%",StringIn)
   LeftPart=""
   if tpos>1 then LeftPart=left(StringIn,tpos-1)
   RightPart=""
   if tpos<(length(StringIn)-2) then RightPart=right(StringIn,1+(length(StringIn)-(tpos+3)))
   StringIn=Leftpart || CmdServer || RightPart
   vpos=pos("%*%",StringIn)
   end

/* Replace %*83% with remote server name in 8.3 format */
vpos=pos("%*83%",StringIn)
CmdServer83=left(CmdServer,8) || "." || right(CmdServer,3)
do while vpos>0
   tpos=pos("%*83%",StringIn)
   LeftPart=""
   if tpos>1 then LeftPart=left(StringIn,tpos-1)
   RightPart=""
   if tpos<(length(StringIn)-2) then RightPart=right(StringIn,1+(length(StringIn)-(tpos+5)))
   StringIn=Leftpart || CmdServer83 || RightPart
   vpos=pos("%*83%",StringIn)
   end

return StringIn
0
 
LVL 22

Accepted Solution

by:
cookre earned 500 total points
Comment Utility
INI file format:
(As with the code, inapplicable parts have been removed)


[EventName1]
Event 1 commands
[EventName2]
Event 2 commands
...
[EventNameN]
Event N commands

Each event name must be unique, but can be made up of any text of arbitrary length.  Events are considered for execution in the order they appear in the event definition file.  The commands used to define a particular event are:


DATE=<DayList>
This required command specifies the days of the week on which the event is to be executed.  
<DayList> is a list of 3-character day name abbreviations separated by commas.  
The recognized abbreviations are: SUN, MON, TUE, WED, THU, FRI, SAT.
Day name abbreviations may appear in any order and case is not important.


TIME=<TimeIntervalList>
This required command specifies one or more time intervals during which the event may be considered for execution (in conjunction with the day(s) specified on the DATE= command).  Time intervals are separated by commas and have the format:
<StartHHMM>-<EndHHMM>
Each HHMM represents a 4-digit hour and minute combination based on a 24-hour clock.
To simplify the specification of events that are to be executed hourly, you may define a single window using '*' for both the beginning and end hour.

Note that there is no requirement that an event be completed within the specified interval.  Rather, the interval is used only to specify a range of acceptable event begin times.


RUNONCE=YES
This optional command indicates that its' associated event is to be executed only once.  The DATE= and TIME= commands are still required.


WAITFILE=<FileName>
This optional command indicates that its' associated event is not to be considered for execution unless <FileName> exists.  To avoid confusion when SERVER= is present, you should fully qualify <FileName> with server and volume.


CMD=<Text>
This command is required for CONSOLE events and specifies the text to be sent to the screen indicated by the NLM= command


;
Any line with a ';' in column one is ignored.

0
 
LVL 22

Expert Comment

by:cookre
Comment Utility
How's it going?
0
 
LVL 8

Expert Comment

by:SNilsson
Comment Utility
Hope you get the points and an A for this Cookre (if the questioneer is still around that is) , you deserve it for all the work you put in to it.
0
 

Author Comment

by:alibabas
Comment Utility
Cookre.... Sorry for the delay.. I was pulled away for something else..
so I did not get a chance to try your code.. actually didn't get a chance to re-engineer it to VB code.  Would still prefer this is VB code if you can.. this way, I can dwalk thru the code in debug mode and learn that way.. Debugging code is better than reading code (for me at least).  From my end... you have got the points and an "A"... just hoping for VB code or more time on my hands to re-engineer the code.. that is why I am leaving this question open for a bit longer. Will give it a few more weeks and than award the points.  Hope you don't mind!

SNilsson - Thank you for givign him credit.. and I definitely plan to give him the points and even if he can't help me with VB code.. he will get an A.. and if someone else comes by now and puts up VB code that works the way I need... Cookre will still get points..
0
 

Author Comment

by:alibabas
Comment Utility
Cookre.. .thank you for your help.. Sorry for delay.. I got busy with something else..
But here are you points and Grade A..
Also.. if you get a chance.. can you try to convert the code to VB?
Thanks.
0
 
LVL 22

Expert Comment

by:cookre
Comment Utility
As it turns out, I just started working on a service that will contain several of these event scheduling features.  Alas, it'll be in C, but, if you're still interested, post something here around mid-February and I'll put up the C code.
0
 

Author Comment

by:alibabas
Comment Utility
Cookre...
Did you ever get to do the code that you spoke about?
I know it has been a long time.. but thought to try.
0
 
LVL 22

Expert Comment

by:cookre
Comment Utility
Sure did, but it's c#.NET.

I'll post it, but I've got to pull out some security specific things first.  
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
maxMirror challenge 10 88
bigHeights  challenge 13 55
powerN  challenge 3 46
array6 challenfge 6 62
Purpose To explain how to place a textual stamp on a PDF document.  This is commonly referred to as an annotation, or possibly a watermark, but a watermark is generally different in that it is somewhat translucent.  Watermark’s may be text or graph…
In this post we will learn how to connect and configure Android Device (Smartphone etc.) with Android Studio. After that we will run a simple Hello World Program.
In this fourth video of the Xpdf series, we discuss and demonstrate the PDFinfo utility, which retrieves the contents of a PDF's Info Dictionary, as well as some other information, including the page count. We show how to isolate the page count in a…
In this fifth video of the Xpdf series, we discuss and demonstrate the PDFdetach utility, which is able to list and, more importantly, extract attachments that are embedded in PDF files. It does this via a command line interface, making it suitable …

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now