home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 2 BBS
/
02-BBS.zip
/
ffmb003.zip
/
FFMB.CMD
Wrap
OS/2 REXX Batch file
|
1994-04-04
|
54KB
|
1,318 lines
/* FFMB.CMD lr0.003 (C)opyright 1994, Dirk Theurer */
/* -------------------------------------------------------------------------
FFMB.CMD lr0.003 (C)opyright 1994, Dirk Theurer
BinkleyTerm-style Flow Filed Mail Bundle handler
Disclaimer:
I've done my best to ensure that everything that FFMB does cannot cause
any problems. However, if you use it, you do so at your own risk. If
you use FFMB then you indicate your agreement to this notice. (I *HATE*
the need for these disclaimers. <sigh>)
Note on these docs:
Sorry if they seem a little higgledy-piggledy. Trying to find some
method of grouping information seemed to be particularly difficult for
FFMB. I hope I've covered everything though.
I refer to specific paths and files here and there. Please change all
such references to suit your system.
Description:
FFMB is a REXX script that "manages" BinkleyTerm-style flow file-
referenced mail bundles according to their size. FFMB's capabilities
are commonly used to ensure that compressed mail bundles do not exceed
some maximum size. FFMB is fully zone-aware, and uses .BSY semaphores
in the same manner as Squish and BinkleyTerm to ensure no collisions
occur with any other .BSY-aware mail processors or mailers.
Where's it useful?
Well, I'm only familiar with the BinkleyTerm/Squish environment. For
this, FFMB does the job. If you run some other mailer/mail processor
combination, you're (mostly) on your own. (Take a look through these
docs anyway to see if it might be of use in your environment. If you
are using SizeMail now, FFMB will most likely be applicable.) Note that
FFMB concerns itself mostly with Squish (no changes are needed to
BinkleyTerm at all). If you use Squish and have it setup to process
mail as in a Bink environment, FFMB will work "as advertised."
Version:
FFMB is in "limited release". This can be interpreted three ways:
1) FFMB is limited (not really - it does what its supposed to);
2) It should only see limited distribution (I don't really care);
3) It's only seen testing on a limited number of systems.
That last one is changing quickly. As soon as I hear from a few people
that have implemented FFMB successfully, I'll change the release type
to "public".
Distribution:
By all means send FFMB to someone you think might find a use for it.
(Heck, give it to ANYONE.) Only thing I ask is that the original
FFMB.CMD file is not modified, and that the compressed filename should
be FFMB###.ext where ### is the version number, and ext is appended by
whatever you use to squash files.
FFMB is FREEWARE. If you find a good use for it, GREAT! (If you cannot
seem to get some "it's so great I could puke" out of your system, send
me mail telling me all about how your gerbil finally convinced you to
use FFMB... the more rice pudding involved, the better.)
What's new:
lr0.003 (04-04-94)
- FFMB now deletes "old" zero-length mail bundles in the mailer's
outbound when necessary.
- Both "Bundle size limiting" and "Cleanup" now invoke FFMB's "FFMB-
cleanup" mode. Basically, this means that invoking FFMB in its
"FFMB-cleanup" mode is not really necessary as it'll be implicitly
run every time FFMB is run. (You can still use FFMB's FFMB-cleanup
mode separately if you want.)
- New option to not report the paths specified on the command line if
a log is asked for. (See command line parameters for modes.)
- Log information types changed a bit (*, +, etc).
- My examples for determining "rule of thumb" settings for limiting
bundle sizes were out to lunch. Hopefully the new ones make more
sense.
- Removed note about "This version of FFMB does NOT limit the size of
un-bundled mail. I might include this in some future version". Non-
bundled mail bundles cannot be limited without mucking about with
odd filenames, and generating custom flow files... (Hmmm... If
anyone can see where limiting the size of uncompressed mail packets
might be of some use, let me know and I'll see what can be done.)
- Someone suggested that perhaps the flow files did not need to be
moved, and that perhaps SizeMail's method of using a single "TMP"
directory would simplify things. At first I thought - "Yeah, why AM
I making things so difficult?" I found out that SizeMail's method
of handling outbounds CAN and WILL cause collisions in a multi-zone
environment (same net/node in different zones). FFMB's method has
no problems with zones. An added benefit is that bundles for nodes
that are .BSY in the mailer's outbound when FFMB starts can STILL
be moved as the .BSY is in the mailer's outbound - not where FFMB
is handling files. (i.e. Moving bundles bound for a node that is
.BSY is a strict no-no.) Some of these benefits came to light
"after the fact", but are there nonetheless. <grin> About the only
down-side to all this is that FFMB must be run at least twice (once
to limit bundle sizes, and then again to move "leftover" bundles
after the mail processor is done).
- My noted worries in the last version about FFMB not handling .BSY
semaphores were apparently related more to worries about Squish's
.BSY semaphores. This is only of concern when there are multiple
copies of Squish running at the same time. As it is, FFMB will not
handle multiple instances of Squish that are tossing to the same
outbound. (*Maybe* some future version will, but only if I get some
requests for such support.)
- I re-organized the docs a bit. Hopefully they're a little more
coherent now.
lr0.002 (03-28-94)
- First limited release.
ir0.001
- Internal release (development).
What does FFMB require?
- FFMB requires a REXX interpreter. (With OS/2, "basic" REXX must be
installed. If you're using some other REXX interpreter, see its
requirements.)
- FFMB - as its description implies - deals (mostly) with mail bundles
referenced by BinkleyTerm-style flow files. (This is not quite true,
but I doubt that you'd want other flow-file referenced files being
"sequenced" the same way as mail bundles.)
- FFMB requires an outbound area for the mail processor SEPARATE from
the one your mailer uses. (See "Installing..." section.)
- In this version, FFMB requires that the two outbound directories
(mailer/mail processor) are on the same drive. (This shouldn't be a
problem as you originally had your single outbound on a single drive,
eh?)
- If you're already aware of BinkleyTerm's and Squish's requirements
for "zone-awareness", you can ignore the following note.
To handle zones properly, FFMB requires that its outbound paths have
no extensions in the last directory name. i.e.
C:\BINK\OUTBOUND OK
C:\BINK\OUTBOUND. OK (FFMB will strip the trailing period)
C:\BINK\OUTBOUND.EXT Not OK
C:\BINK.EXT\OUTBOUND OK
C:\BINK.EXT\OUTBOUND.EXT Not OK
FFMB will generate an error message and exit if an extension is
specified for the last directory name of either outbound.
Howzzit work?
In "Bundle size limiting" mode (see "FFMB modes" section), FFMB looks
through Squish's outbound area and sees if any flow-file referenced
files are larger than you specify. If a "over-size" file is found, the
mailer's outbound is checked for any files that have the same root
filename. FFMB finds the next sequence number for that root filename.
FFMB then renames/moves the file to the mailer's outbound with this new
sequence number. (Sequences are 0 to 9, and A to Z.) FFMB then moves
the associated flow file to one of two areas: if no .BSY semaphore
exists in your mailer's outbound for this zone:net/node, the flow file
is moved to the mailer's outbound for this zone; if a .BSY semaphore is
found, the flow file is moved to FFMB's "hold" area for the current
zone. (FFMB's "hold" areas are always a $$FFMB$$.TMP directory in your
mailer's outbound for the current zone.)
Notes: - "Root filename" for FFMB means the "filename.dd" portion of
"filename.dd?". The "?" is the sequence number. Squish's
sequence number is ignored by FFMB, as the only place sequence
numbers are of importance is in your MAILER'S outbound.
- FFMB simply *moves* the file (with the new name in its new
directory). This means that Squish will tend to generate the
same sequence number over and over (usually 0). This should
NOT cause any problems, but FFMB does not have any problems
when files with some other sequence numbers are in Squish's
outbound. (Confused? _I_ am. <grin>)
In "Cleanup" mode, FFMB will move ALL files in Squish's outbound area,
using all the other rules for the "Bundle size limiting" mode.
FFMB also has a separate mode ("FFMB-cleanup") that just checks its own
holding areas for any flow files that were previously .BSY. It still
checks for matching .BSY semaphores in the mailers outbound, but will
move all "non-.BSY" files (flowed or not) to the mailer's outbound.
Notes: - FFMB-handled flow files are always *appended* to a flow file
in either your mailer's outbound, or in FFMB's holding area if
a .BSY semaphore was encountered for that flow file.
- Files in Squish's outbound that are not referenced by flow
files are only handled in FFMB's "Cleanup" mode. FFMB will
always indicate that these are "orphan" or "non-flow" files.
(Perhaps a little misleading, but FFMB is supposed to only be
dealing with flow-file referenced mail bundles. <grin>) This
includes NON-BUNDLED MAIL (.PKT, ?UT, etc). Any files that are
not referenced by flow files are moved either to your mailer's
outbound, or to FFMB's holding area if a .BSY equivalent is
in your mailer's outbound. These are moved at the same time
and the same way as other flow files that might be in FFMB's
holding area when FFMB is run in "FFMB-cleanup" mode.
FFMB modes:
Notes: - FFMB can be run in any mode at any time. There are no entrance
or exit requirements except that directories must be specified
where indicated, and those directories must exist.
- Command line parameters are not case-sensitive, and trailing
back-slashes for directory specifications are optional.
Bundle size limiting
FFMB will move any flow files and their associated bundles that
exceed a specified size from your mail processor's outbound to where
your mailer expects to find outbound mail and files.
This mode is commonly run from a mail processor during "breaks" (see
Squish.Cfg's MaxMsgs keyword, and Squish-Route.Cfg's DOS keyword).
FFMB command line parameters for bundle size limiting:
Max_bytes Originating_outbound Destination_outbound [Log_name [*]]
- Max_bytes *Required* All bundles that exceed this
limit are moved from Originating_outbound
to Destination_outbound.
- Originating_outbound *Required* Where your mail processor places
outbound bundles.
- Destination_outbound *Required* Where your mailer expects to
find outbound stuff (mail, bundles, flow
files, etc).
- Log_name (Optional) Log file of FFMB activity.
- * (Optional but requires Log_name) Disables
some path reporting in the log. ("*" can be
ANYTHING - if it's non-blank, FFMB will not
log "Orig./Dest. path".)
Example:
FFMB 500000 C:\SQUISH\OUTBOUND C:\BINK\OUTBOUND C:\LOG\FFMB.LOG
Note: This mode only handles FLOW FILES and the files they reference.
FFMB will NOT look for or handle ANY other files in this mode.
Cleanup after your mail processor
This mode is similar to the size limiting mode except that ALL files
in Originating_outbound are moved to Destination_outbound. FFMB will
move all flow files and their associated bundles (properly sequenced)
to your mailer's outbound area. FFMB checks for .BSY semaphores and
leaves flow files that match them in it's own holding area. All other
files that remain in Originating_outbound are then moved to your
mailer's outbound (also using .BSY rules). (Any files not referenced
by flow files are noted as "orphan" or "non-flowed".)
This mode is normally run after your mail processor has exited.
FFMB command line parameters for cleanup after your mail processor
C[LEANUP] Originating_outbound Destination_outbound [Log_name [*]]
- CLEANUP *Required* Tells FFMB to move *everything*
from Originating_outbound to Destination_
outbound.
- Originating_outbound *Required* Where your mail processor places
outbound bundles.
- Destination_outbound *Required* Where your mailer expects to
find outbound files (mail, bundles, flow
files, etc).
- Log_name (Optional) Log file of FFMB activity.
- * (Optional but requires Log_name) Disables
some path reporting in the log. ("*" can be
ANYTHING - if it's non-blank, FFMB will not
log "Orig./Dest. path".)
Example:
FFMB CLEANUP C:\SQUISH\OUTBOUND C:\BINK\OUTBOUND C:\LOG\FFMB.LOG
Note: Only the first character of the CLEANUP parameter is required.
FFMB-cleanup to move previously .BSY flow files
Cleans up FFMB's holding area(s) if possible. FFMB will not write to
flow files in your mailer's outbound area if a .BSY semaphore exists
for a node. Running FFMB in this mode checks if those .BSY semaphores
still exist, and if not, move the flow files for such nodes. This
mode should be run often to ensure that flow files are moved from
FFMB's holding area to your Binkley-style outbound as quickly as
possible. (Suggestion: Run this mode after ALL mail processor exits,
and also before you start your mailer.)
FFMB command line parameters to move previously .BSY flow files
F[FMBCLEANUP] Destination_outbound [Log_name [*]]
- FFMBCLEANUP *Required* Tells FFMB to check its own hold
areas and move everything it can into
Destination_outbound.
- Destination_outbound *Required* Where your mailer expects to
find outbound files (mail, bundles, flow
files, etc).
- Log_name (Optional) Log file of FFMB activity.
- * (Optional but requires Log_name) Disables
some path reporting in the log. ("*" can be
ANYTHING - if it's non-blank, FFMB will not
log "Orig./Dest. path".)
Example:
FFMB FFMBCLEANUP C:\BINK\OUTBOUND C:\LOG\FFMB.LOG
Notes: - The Originating_outbound needed for other modes is not
needed here. (FFMB looks only for its own holding areas in
this mode.)
- Only the first character of the FFMBCLEANUP parameter is
required.
- FFMB will not create any holding areas when cleaning up
after itself. It checks only for previously created areas.
Installing FFMB for Squish:
Notes: - The following outlines how to install FFMB for Squish ONLY! If
you are using some other mail processor, please go through
these docs carefully, and if it is not clear what's going on,
let me know.
- Mailer/mail processor environments vary WILDLY! This section
outlines the basic stuff. If you have something substantially
different, just make sure you know what FFMB actually does.
- Copy FFMB.CMD to a directory listed in your PATH.
- Create a new directory - WITHOUT an extension in its name - for
Squish's outbound. (You can delete Squish's old *.SQ directory
parallel to your mailer's outbound. Squish will re-create it parallel
to its new outbound.)
- Change Squish's configuration Outbound keyword to match this new
directory. For example, if your original Squish and Bink were
configured to place/look for mail in C:\BINK\OUTBOUND, create a
new directory called C:\SQUISH\OUTBOUND, and change the OutBound
config keyword in Squish.Cfg to C:\SQUISH\OUTBOUND. No changes to
Bink's config.
- If you do not already have a MaxMsgs entry in your Squish.Cfg, add a
line similar to:
MaxMsgs 500
(Check the Squish docs for what this does.) I've noticed that in
Fidonet, a "MaxMsgs 500" tends to produce compressed bundles of about
400K for nodes receiving all message areas. A workable rule of thumb
is to take the maximum size (in K) you want your bundles to be, add
10% and set MaxMsgs to this number. To move bundles of about this
size get moved by FFMB, subtract about 35% from this MaxMsgs setting,
multiply by 1000, and use the result for FFMB's Max_bytes parameter.
For example, if you wanted to limit bundles to average ~500K, set
MaxMsgs to 550, and use 350000 for Max_bytes with FFMB. This'll get
you ARC bundles of 350K to 700K. To make FFMB's Max_bytes parameter
more closely match the bundle sizes you want, decrease the MaxMsgs
settings (FFMB will get a chance to check bundle sizes oftener, but
you'll have smaller, and more PKTs in the bundles). Of course your
mileage will vary WILDLY. Play with it.
- In your Route.Cfg, append a line at the very end to read similar to:
DOS FFMB 350000 C:\SQUISH\OUTBOUND C:\BINK\OUTBOUND C:\LOG\FFMB.LOG
where: 350000 maximum bundle size in bytes
C:\BINK\OUTBOUND your mailer's outbound
C:\SQUISH\OUTBOUND Squish's OutBound area
C:\LOG where you keep your logs (optional)
Notes: - FFMB cannot control how large bundles actually get. Squish
must exit and execute FFMB before FFMB can do any bundle
size limiting. The key here is Squish.Cfg's MaxMsgs value.
- The "DOS FFMB..." line can be placed anywhere in Route.Cfg,
but Squish has its own rules for when it might be used. If
it's placed at the very end of Route.Cfg, Squish will always
bundle up ALL mail to be bundled, and then look at the "DOS"
line.
- In your mail processing batch or CMD file, add a reference to FFMB so
that FFMB can cleanup after each Squish run. (This ensures that all
mail bundles from Squish are moved to your mailer's outbound.) REXX
example:
Squishp in out squash -o
"CALL FFMB C C:\SQUISH\OUTBOUND C:\BINK\OUTBOUND C:\LOG\FFMB.LOG"
Squishp squash
"CALL FFMB C C:\SQUISH\OUTBOUND C:\BINK\OUTBOUND C:\LOG\FFMB.LOG"
signal BINKLEY
Batch file example:
Squishp in out squash -o
CALL FFMB C C:\BINK\OUTBOUND C:\SQUISH\OUTBOUND C:\LOG\FFMB.LOG
Squishp squash
CALL FFMB C C:\BINK\OUTBOUND C:\SQUISH\OUTBOUND C:\LOG\FFMB.LOG
goto BINKLEY
- If you want to ensure that .BSY flow files are moved regularly, add
another line immediately before your mailer starts up. REXX example:
"CALL FFMB F C:\BINK\OUTBOUND C:\LOG\FFMB.LOG"
btp
Batch file example:
CALL FFMB F C:\BINK\OUTBOUND C:\LOG\FFMB.LOG
btp
That's about it!
"Left-over" notes:
- FFMB creates and uses its own "flow file holding area(s)". These are
ALWAYS created as a subdirectory off of Destination_outbound. These
directories can be removed if they are empty *AND* FFMB is not
running. (FFMB will re-create any that are needed on its next run.)
- If FFMB encounters an outbound zone for Squish that does not already
exist for your mailer, it will be created also.
- "Stray bundles" in your outbound have NOT actually strayed at all!
Check FFMB's holding area ($$FFMB$$.TMP in your mailer's outbound)
for the flow files that reference them. (FFMB writes ALL "oversize"
or "cleanup" files referenced by flow files to the outbound area
without checking for .BSY semaphores. HOWEVER, FFMB will *NOT* mess
with any flow files in your mailer outbound area if a .BSY semaphore
is set for a node. All flow information is written to FFMB's area
instead.)
- This version of FFMB will NOT handle multiple instances of Squish
running at the same time! (i.e. Squish is processing mail while FFMB
is running.) I don't know if/when such support will be added to FFMB.
Note that if Squish is processing mail in a DIFFERENT "originating"
outbound than FFMB is currently processing, there should be no
problem. Just use a different FFMB log names for possible multiple
instances of FFMB.
- Why FFMB? Well, I'm getting REAL tired of running DOS software under
OS/2. SizeMail is the only utility that provides this functionality
(that I know of), but it is "yet another crippling DOS utility".
I should add here that FFMB is *not* a SizeMail clone or "look-
alike". It's functionality is quite similar, but FFMB and SizeMail
work within substantially different paradigms. (I didn't really look
at the what and how of SizeMail until I was just about finished with
the first release of FFMB.)
- Why REXX? Four reasons:
1) Because I wanted to.
2) REXX interpreters are available for a variety of platforms.
3) I VERY MUCH like my software to be as configurable/customizable as
absolutely possible. I can think of nothing more flexible that a
reasonably preforming interpreted language in which the utility
can be distributed in source form. This gives the user the
ULTIMATE in flexibility! <grin>
4) Because I wanted to. (Did I just say that twice? Musta been cuz I
wanted to.)
- I'm hoping that the next version of Squish will obviate any need for
FFMB (or equivalent). I feel that Squish should be able to manage
bundles sizes without any "outside" help.
Support:
FFMB and its REXX format present problems with support. Any Tom, Dick,
and/or Hairy can dink with the CMD itself, and pass it on. This being
the case, I can properly support FFMB only if you send me the COMPLETE,
ORIGINAL copy you are using. If you don't send me a copy, and I can't
reproduce the problem, you're on your own. (Maybe FReq the most recent
version from me instead - even if it appears to be the same version, it
could very well be different, depending on who's messed with it before
you got it.)
Along with a copy of the FFMB.CMD you have, send along any pertinent
information (directory specs used, list of files for each, FFMB log
samples, command line parameters used, any error messages you got on
the screen that don't occur in FFMB's log, etc).
If you have a mail processor that you think FFMB should work with,
please send me the name and latest version number of the processor.
Note: Do NOT send me a copy of your mail processor! Name and version
only, please. (I've probably already got it. <grin> If I don't,
I'll try to find it locally.)
Contact info:
Comments, suggestions, bug reports, etc about FFMB are welcomed! I can
be reached as: - Netmail to Dirk Theurer 1:153/828@fidonet
- e-mail to dirk.theurer@iflex.wimsey.com
Latest version of FFMB can be FReq'd from above Fidonet address as
"FFMB" (without the quotes). If you want it sent via Internet e-mail,
request such from your e-mail address, and I'll send a UUENCODEd copy
of the (PK)ZIP v2.x format distribution copy as (however many) less-
than-8K messages. (Requests to "gate" e-mail copies to Fidonet via
Internet will be ignored!)
A good suggestion:
Move all these leading comments (except the first "REXX-identifying"
line) to some other text file. FFMB should load a little faster then.
(Keep the original package you got in case you need support though. I
really DO require that I get a "matchable" copy to support FFMB
properly.)
Enjoy!
------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------
Note to (wanna-be) REXX tinkerers:
FFMB.CMD lr0.003 is not a trivial REXX script. Dink with it at your own
risk.
I mentioned in the last version that perhaps this script would be re-
organized. I've gone over it and it doesn't seem to need it as badly as I
thought.
Changes from previous versions are NOT noted anywhere! ANYTHING can be,
and is changed whenever I feel like (usually to make things easier to
read, conserve memory, increase performance, and sometimes just for the
heck of it).
I am quite aware that some things could be done much easier by invoking
REXXUTIL, but I'll sacrifice script readability and portability over
memory any day.
------------------------------------------------------------------------- */
"@echo off"
arg ffmbmode origdir destdir logname logpaths
/* reset elapsed time timer */
starttime=time(R)
call initffmb
/* debug is used to display various info while script is developed. Set */
/* this to 0 if not needed (do NOT just remove this statement). */
/* Note: Limited release versions of FFMB have debug set to 0. Set to 1 */
/* if you want additional information displayed on-screen. */
debug=0
/* first parameter exists? */
if ffmbmode="" then
call PRELOGFFMBERROR 1 "No mode specified."
/* determine mode */
sizelimit=0
select
when left(ffmbmode,1)="C" then /* Cleanup */
ffmbmode="C"
when left(ffmbmode,1)="F" then /* FFMB-cleanup */
ffmbmode="F"
otherwise do /* Bundle size limiting */
if datatype(ffmbmode)<>"NUM" then
call PRELOGFFMBERROR 1 "Invalid byte limit specified."
else
if ffmbmode<0 then
call PRELOGFFMBERROR 1 "Negative(?!?) byte limit specified."
sizelimit=ffmbmode
ffmbmode="S"
end
end
if ffmbmode="F" then do
/* shuffle command line parameters (no origdir for FFMB-cleanup) */
logpaths=logname
logname=destdir
destdir=origdir
origdir=""
end
else do
/* all other modes require origdir */
origdir=verifydir(origdir,"Originating outbound")
/* get pattern for originating directory name */
origpattern=left(origdir,length(origdir)-1)
end
/* destdir is required for all modes */
destdir=verifydir(destdir,"Destination outbound")
/* get pattern for destination directory name */
destpattern=left(destdir,length(destdir)-1)
/* verify/setup optional log stuff */
if logname="" then
say "* "logdatetime()" "cmdname" (No log)"
else
if \findfile(logname) then do
if \openappend(logname) then
call PRELOGFFMBERROR 1 logname" cannot be opened for writing."
ot=lineout(logname,"")
ot=lineout(logname," "cmdname" "cmdvers" "cmdcopy)
ot=lineout(logname," "cmddesc)
ot=lineout(logname," "left("",76,"─"))
ot=lineout(logname,"")
say " "logdatetime()" "cmdname" Log file: "logname" (created)"
end
else do
if \openappend(logname) then
call PRELOGFFMBERROR 1 logname" cannot be opened for writing."
say " "logdatetime()" "cmdname" Log file: "logname
end
/* verify that origdir and destdir exist */
/* save current dir (dir tests are done by trying to change to those */
/* directories) */
savedir=directory()
if ffmbmode<>"F" then
if \changedir(origdir) then
call FFMBERROR 1 origdir" does not exist."
if \changedir(destdir) then
call FFMBERROR 1 destdir" does not exist."
/* used for all FFMB-specific and temporary stuff */
ffmbfile="$$FFMB$$"
/* restore current directory */
ot=directory(savedir)
select
when ffmbmode="F" then do
call writelog logname,"*","FFMB-cleanup"
signal FFMBCLEANUP
end
when ffmbmode="C" then do
call writelog logname,"*","Cleanup"
signal FFMBMOVEBUNDLES
end
otherwise do
call writelog logname,"*","Move bundles > "sizelimit" bytes"
signal FFMBMOVEBUNDLES
end
end
/* That's it! Everything else is signalled or called. */
FFMBMOVEBUNDLES:
/* ------------------------------------------------------------------------
Non-cleanup mode (move oversize files only) for all detectable zones
- get zone list (directory list of origdir.*)
- move bundles in base zone
- loop through remaining zones
- move bundles in current zone
- run FFMBCLEANUP mode
------------------------------------------------------------------------ */
if logpaths="" then do
call writelog logname,":","Orig. path: "origdir
call writelog logname,":","Dest. path: "destdir
end
/* ffmbdir is FFMB's "holding" area for flowfiles that have .BSY semaphores */
ffmbdir=destdir""ffmbfile".TMP\"
/* if FFMB's holding area doesn't exist, try to create it */
if \changedir(ffmbdir) then
if \makedir(ffmbdir) then
call FFMBERROR 1 ffmbdir" could not be created."
if findfile(origdir"*.*") then do
if ffmbmode="C" | findfile(origdir"*.?LO") then do
call writelog logname," ","Processing default zone:"
call FFMBMOVEZONE
call writelog logname,"*","Moved "movedflowed" flowed file(s) for default zone."
if ffmbmode="C" & movedunflowed<>0 then
call writelog logname,"*","Moved "movedunflowed" non-flowed file(s) for default zone."
end
end
/* get zone directory list */
call getzonelist origpattern,origdir""ffmbfile".$$$"
if debug then
do i=1 to zonelist.0; say "DEBUG Zone directory "right(" "i,3)": "zonelist.i; end
do zone=1 to zonelist.0
origdir=zonelist.zone
/* extract hex-zone */
zonei=substr(origdir,lastpos(".",origdir)+1)
/* add backslash to new origdir */
origdir=origdir"\"
if findfile(origdir"*.*") then do
if ffmbmode="C" | findfile(origdir"*.?LO") then do
call writelog logname," ","Processing zone "x2d(zonei)" ("zonei"h):"
/* setup new destdir */
destdir=destpattern"."zonei"\"
/* if destdir for this zone does not exist, create it */
if \changedir(destdir) then
if \makedir(destdir) then
call FFMBERROR 1 destdir" (zone "x2d(zonei)") could not be created."
/* setup FFMB's "holding" area for this zone */
ffmbdir=destdir""ffmbfile".TMP\"
/* if FFMB's holding area doesn't exist, try to create it */
if \changedir(ffmbdir) then
if \makedir(ffmbdir) then
call FFMBERROR 1 ffmbdir" (zone "x2d(zonei)") could not be created."
/* return to default directory after dir checks */
ot=directory(savedir)
call FFMBMOVEZONE
call writelog logname,"*","Moved "movedflowed" flowed file(s) for zone "x2d(zonei)"."
if ffmbmode="C" & movedunflowed<>0 then
call writelog logname,"*","Moved "movedunflowed" non-flowed file(s) for zone "x2d(zonei)"."
end /* flow files exist for zone, or in cleanup mode */
end /* files exist for zone */
end /* zone list loop */
/* setup for FFMB-cleanup mode */
origdir=origpattern"\"
destdir=destpattern"\"
call writelog logname,"*","Implied FFMB-cleanup"
signal FFMBCLEANUP
FFMBCLEANUP:
/* ------------------------------------------------------------------------
Move non-.BSY flow files for all detectable zones from FFMB's holding
area(s).
- move non-.BSY flow files to outbound (destdir) for default zone
- get zone list (directory list of destdir.*)
- loop through remaining zones
- move non-.BSY flow files to outbound (destdir) for current zone
- exit
------------------------------------------------------------------------ */
if ffmbmode="F" & logpaths="" then
call writelog logname,":","Path: "destdir
/* define ffmb's holding area */
ffmbdir=destdir""ffmbfile".TMP\"
if findfile(ffmbdir"*.*") then do
call writelog logname," ","Processing default zone:"
call FFMBCLEANUPZONE
call writelog logname,"*","""Unhold"" "movedflow" flow / "movednonflow" non-flow file(s) for default zone."
end
/* get zone directory list */
call getzonelist destpattern,destdir""ffmbfile".$$$"
if debug then
do i=1 to zonelist.0; say "DEBUG Zone directory "right(" "i,3)": "zonelist.i; end
do zone=1 to zonelist.0
destdir=zonelist.zone
/* extract hex-zone */
zonei=substr(destdir,lastpos(".",destdir)+1)
/* add backslash to new destdir */
destdir=destdir"\"
/* define FFMB's "holding" area for this zone */
ffmbdir=destdir""ffmbfile".TMP\"
/* process zone if FFMB's holding area exists and something is in it */
if findfile(ffmbdir"*.*") then do
call writelog logname," ","Processing zone "x2d(zonei)" ("zonei"h):"
call FFMBCLEANUPZONE
call writelog logname,"*","""Unhold"" "movedflow" flow / "movednonflow" non-flow file(s) for zone "x2d(zonei)"."
end
end /* zone list loop */
signal ENDFFMB
FFMBMOVEZONE:
/* ------------------------------------------------------------------------
Process:
- Get list of ?lo files from origdir
- Go through ?lo file list
- current flow file
- if bundle larger than sizelimit:
- re-sequence and move bundle to destdir
- write flow entry to ffmb flow file
- else
- write flow entry to temp flow file
- when flow file finished:
- if any bundles not moved:
- ren temp flow file to orig flow filename
- else
- del temp flow file
- if ffmb flow file movable to destdir, move (append) it
------------------------------------------------------------------------ */
/* get list of ?LO files in origdir */
call getfilelist origdir"*.?LO",ffmbdir""ffmbfile".$$$"
if debug then
do i=1 to filelist.0; say "DEBUG Flow file "right(" "i,3)": "filelist.i; end
/* initialize number of files moved */
movedflowed=0
movedunflowed=0
/* temporary flow file */
tempflow=origdir""ffmbfile".FLW"
/* go through all flow files and verify/move/whatever bundles */
do i=1 to filelist.0
/* delete temp flow file if it exists */
if findfile(tempflow) then do
call closefile tempflow
"del "tempflow
end
ffmbflow=ffmbdir""filespec("N",filelist.i)
if debug then do
say "DEBUG Originating flowfile: "filelist.i
say "DEBUG Destination flowfile: "ffmbflow
say "DEBUG Temporary flowfile: "tempflow
end
/* loop through list of bundles in flow file */
holdbundles=0 /* count how many are NOT moved to outbound */
call openread filelist.i
do while lines(filelist.i)
origname=translate(linein(filelist.i))
if debug then say "DEBUG Bundle line: "origname
/* determine bundle type (delete/truncate/keep) */
if left(origname,1)="^" then do
origtype="^" /* delete (don't think this is ever used) */
origname=substr(origname,2)
end
else
if left(origname,1)="#" then do
origtype="#" /* truncate (the norm?) */
origname=substr(origname,2)
end
else
origtype="" /* keep (don't think this is ever used) */
/* end of bundle type */
if \findfile(origname) then
call writelog logname,"!"," - NO FILE: "origname" (orphan flow entry)"
else do
/* if in cleanup mode, or if bundle is larger that "sizelimit" */
if ffmbmode="C" | stream(origname,"C","Query size")>sizelimit then do
/* got a bundle to move */
call writelog logname," ","Orig. file: "origname" ("stream(origname,"C","Query size")")"
/* bundle name minus sequence number */
testname=filespec("N",origname)
testname=left(testname,pos(".",testname)+2)
if findfile(destdir"*."right(testname,2)"*") then do
/* see if old bundles are zero length and old */
tempfile=origdir""ffmbfile".$$$"
"dir /f /a-d /od "destdir"*."right(testname,2)"* > "tempfile
call openread tempfile
do while lines(tempfile)
readline=linein(tempfile)
if stream(tempfile,"C","Query size")<>0 then do
if oldfile(readline)>4 then
"del "readline
else /* we can quit on first file encountered that is not old */
leave
end
end
call closefile tempfile
"del "tempfile
end
/* find unique sequence number for bundle in destdir */
do seq=0 to 9
destname=destdir""testname""seq
if movebundle(origname,destname) then
leave seq
end
if seq>9 then do
do seq2=65 to 90 /* try "A" to "Z" */
destname=destdir""testname""d2c(seq2)
if movebundle(origname,destname) then
leave seq2
end
end
if debug then do
say "DEBUG Old bundle name: "origname
say "DEBUG Old flow entry: "origtype""origname
say "DEBUG New bundle name: "destname
say "DEBUG New flow entry: "origtype""destname
end
/* finally get to actually MOVE something (yeow) */
call writelog logname,"+"," Moved to: "destname
ot=lineout(ffmbflow,origtype""destname)
movedflowed=movedflowed+1
end /* bundle was over size limit */
else do /* bundle is not over size limit */
holdbundles=1
ot=lineout(tempflow,origtype""origname)
end
end
end /* end of bundles in flow file */
call closefile filelist.i
call closefile tempflow
call closefile ffmbflow
"del "filelist.i
if findfile(tempflow) then
if holdbundles then
"ren "tempflow" "filespec("N",filelist.i)
else
"del "tempflow
/* if new flow file exists, try to move it to outbound area */
if findfile(ffmbflow) then
call moveflowfile ffmbflow
end /* end of current flow file */
/* if in cleanup mode and files remain in origdir, move 'em */
if ffmbmode="C" & findfile(origdir"*.*") then do
/* get files listing */
/* NOTE! The temporary file to get this listing must !_*NOT*_! use the */
/* same directory as that for the files being listed! We know the */
/* ffmbdir exists, so use it instead. */
call getfilelist origdir"*.*",ffmbdir""ffmbfile".$$$"
do i=1 to filelist.0
/* construct destdir .bsy name */
destbusy=filespec("N",filelist.i)
destbusy=destdir""left(destbusy,pos(".",destbusy))"BSY"
/* if destdir .bsy exists, destname is ffmbdir{}, else destdir{} */
if findfile(destbusy) then
destname=ffmbdir""filespec("N",filelist.i)
else
destname=destdir""filespec("N",filelist.i)
if debug then do
say "DEBUG Originating filename: "filelist.i
say "DEBUG Destination filename: "destname
end
if \findfile(destname) then do
call movefile filelist.i,destname
call writelog logname, "+"," Orphan to: "destname
movedunflowed=movedunflowed+1
end
else
call writelog logname, "-"," Dupe file: "filelist.i
end
end
return
FFMBCLEANUPZONE:
/* ------------------------------------------------------------------------
Process:
- get list of files in ffmbdir and go through them
- construct destdir .bsy filename
- if file is ?LO, then
- try to move flow file (see MOVEFLOWFILE)
- else
- if outbound area does not have a matching .bsy file, then
- create/hold .bsy file
- move file to destdir
- close/delete .bsy file
------------------------------------------------------------------------ */
/* get list of files in ffmbdir */
/* NOTE! The temp file spec for retrieving this file list must !_*NOT*_! */
/* use the same directory as for the files being listed! We know that */
/* destdir exists, so use it instead. */
call getfilelist ffmbdir"*.*",destdir""ffmbfile".$$$"
if debug then
do i=1 to filelist.0; say "DEBUG File "right(" "i,3)": "filelist.i; end
movedflow=0
movednonflow=0
do i=1 to filelist.0
if right(filelist.i,2)="LO" then
movedflow=movedflow+moveflowfile(filelist.i)
else do
/* construct .bsy filename */
destbusy=filespec("N",filelist.i)
destbusy=destdir""left(destbusy,pos(".",destbusy))"BSY"
if debug then do
say "DEBUG Dest. flow busy file: "destbusy
say "DEBUG Originating filename: "filelist.i
say "DEBUG Destination filename: "destdir""filespec("N",filelist.i)
end
if \findfile(destbusy) then do
ot=lineout(destbusy,cmdname" "cmdvers" is holding this file open")
destname=destdir""filespec("N",filelist.i)
if \findfile(destname) then do
call movefile filelist.i,destname
call writelog logname,"+","Dest. file: "destname
call closefile destbusy
"del "destbusy
movednonflow=movednonflow+1
end
else
call writelog logname, "-"," Dupe file: "filelist.i
end
else
call writelog logname,"+"," Hold file: "filelist.i
end
end
return
ENDFFMB:
/* ------------------------------------------------------------------------
Clean things up
------------------------------------------------------------------------ */
/* switch back to original directory */
test=directory(savedir)
/* figure out elapsed time */
seconds=trunc(time(E))
minutes=trunc(seconds/60)
seconds=seconds-(minutes*60)
if seconds<10 then seconds="0"seconds
/* cleanup log */
call writelog logname,"*","Elapsed: "minutes" min "seconds" sec"
call writelog logname,""
exit 0
/* ------------------------------------------------------------------------
Error routines
------------------------------------------------------------------------ */
PRELOGFFMBERROR:
parse arg rlevel errormsg
say "! "logdatetime()" "cmdname" ERROR: "errormsg
say ""
call honk
exit rlevel
FFMBERROR:
parse arg rlevel errormsg
call writelog logname,"!","ERROR: "errormsg
call writelog logname,""
call honk
exit rlevel
/* ------------------------------------------------------------------------
"CALLed" routines and functions specific to FFMB
------------------------------------------------------------------------ */
INITFFMB:
cmdname="FFMB"
cmdvers="lr0.003"
cmdcopy="(C)opyright 1994, Dirk Theurer"
cmddesc="BinkleyTerm-style Flow-Filed Mail Bundle handler"
say ""
say " "cmdname" "cmdvers" "cmdcopy
say " "cmddesc
say " "left("",76,"─")
return
HONK:
do 3; call beep 2300,100; call beep 20000,25; end
return
GETFILELIST:
arg filelistspec,tempfilelist
/* WARNING: DIR's /a-d switch ensures that only FILES are listed. */
if findfile(filelistspec) then do
"dir /f /a-d /on "filelistspec" > "tempfilelist
call openread tempfilelist
fn=0
do while lines(tempfilelist)
fn=fn+1
filelist.fn=translate(linein(tempfilelist))
end
filelist.0=fn
call closefile tempfilelist
"del "tempfilelist
return
end
fn=0
filelist.0=fn
return
GETZONELIST:
arg zonelistspec,tempzonelist
/* WARNING: DIR's /ad switch ensures that only directories are listed. */
"dir /f /ad /on "zonelistspec".* > "tempzonelist
call openread tempzonelist
fn=0
do while lines(tempzonelist)
readline=translate(linein(tempzonelist))
temppos=lastpos(".",readline)+1
if temppos>1 then do
readlineext=substr(readline,temppos)
/* is extracted extension is a "legit" zone spec length? */
if length(readlineext)<4 then do
/* if extension is a hex value, then accept the dir spec */
if datatype(readlineext,"X") then do
fn=fn+1
zonelist.fn=readline
end
end
end
end
zonelist.0=fn
call closefile tempzonelist
"del "tempzonelist
return
MOVEFLOWFILE:
/* -----------------------------------------------------------------------
Process:
- construct destdir .bsy filename
- if destdir does not have .bsy file, then
- create/hold .bsy file
- move (append) flow file to destdir
- close/delete .bsy file
------------------------------------------------------------------------ */
arg mfffilename
flowbusy=filespec("N",mfffilename)
flowbusy=destdir""left(flowbusy,pos(".",flowbusy))"BSY"
destflow=destdir""filespec("N",mfffilename)
if debug then do
say "DEBUG Dest. flow busy name: "flowbusy
say "DEBUG Dest. flow name: "destflow
end
/* move (append) to destdir if .BSY file not found */
if \findfile(flowbusy) then do
ot=lineout(flowbusy,cmdname" "cmdvers" is holding this file open")
call writelog logname,"+","Dest. flow: "destflow
call openread mfffilename
do while lines(mfffilename)
flowline=linein(mfffilename)
ot=lineout(destflow,flowline)
end
call closefile destflow
call closefile mfffilename
"del "mfffilename
call closefile flowbusy
"del "flowbusy
return 1
end
else do
call writelog logname,"+"," Hold flow: "mfffilename
return 0
end
MOVEBUNDLE:
/* Moves bundle to destination if it doesn't exist (removes leading drive */
/* in destination bundle file spec) */
/* NOTE: This routine is (currently) limited to moving files around on the */
/* SAME drive! */
arg origmovebundle, destmovebundle
destmovebundle=filespec("P",destmovebundle)""filespec("N",destmovebundle)
if findfile(destmovebundle) then
return 0
else do
"move "origmovebundle" "destmovebundle" > nul"
return 1
end
VERIFYDIR:
parse arg verifydirspec, errormessage
if verifydirspec="" then do
say "! "logdatetime()" "cmdname" ERROR: "errormessage" not specified."
call honk
exit 1
end
/* ensure that dir spec does NOT include a period in the last dir spec */
if right(verifydirspec,1)="\" then
verifydirspec=left(verifydirspec,length(verifydirspec)-1)
/* I cheat a little on this one by using filespec()'s "Name" default of */
/* accepting ANYthing at the end as a filename if it does not have a */
/* trailing back-slash. */
tempdirspec=filespec("N",verifydirspec)
/* if the period is trailing, simply eliminate it */
if right(tempdirspec,1)="." then
verifydirspec=left(verifydirspec,length(verifydirspec)-1)
else do
/* if period is not trailing, it's "illegal" for Bink/Squish outbounds */
if pos(".",tempdirspec)<>0 then do
say "! "logdatetime()" "cmdname" ERROR: "errormessage" contains illegal period."
call honk
exit 1
end
end
/* ensure that dir spec includes trailing backslash */
verifydirspec=verifydirspec"\"
return verifydirspec
MAKEDIR:
arg makedirspec
if right(makedirspec,1)="\" then
"md "left(makedirspec,length(makedirspec)-1)
else
"md "makedirspec
makedirsave=directory()
if \changedir(makedirspec) then do
makedirsave=directory(makedirsave)
return 0
end
else do
makedirsave=directory(makedirsave)
return 1
end
WRITELOG:
parse arg writelogfile, writelogtype, writeloginfo
if length(writelogtype)=0 then do
say ""
writelogtemp=lineout(writelogfile,"")
end
else do
writelogtemp=writelogtype" "logdatetime()" "cmdname" "writeloginfo
say writelogtemp
if writelogfile<>"" then do
writelogtemp=lineout(writelogfile,writelogtemp)
end
end
return
/* ------------------------------------------------------------------------
"CALLed" routines and functions not specific to FFMB
------------------------------------------------------------------------ */
CHANGEDIR: /* changes to passed directory */
arg dirtochangeto
dirtochangeto=strip(dirtochangeto)
if right(dirtochangeto,1)="\" then do /* new dir has a trailing backslash */
changedirtemp=directory(left(dirtochangeto,length(dirtochangeto)-1))
if changedirtemp<>"" then
return 1
else
return 0
end
else do /* dirtochangeto does not contain a trailing backslash */
changedirtemp=directory(dirtochangeto)
if changedirtemp<>"" then
return 1
else
return 0
end
CLOSEFILE:
arg closefilefile
closefiletest=stream(closefilefile,"C","Close")
if left(closefiletest,5)<>"READY" then
return 0
else
return 1
FINDFILE:
arg findfilename
if stream(findfilename,"C","Query exists")<>"" then
return 1
else
return 0
LOGDATETIME:
td=substr(date(),1,6)
if substr(td,6,1)=" " then td="0"substr(td,1,5)
tdt=td" "time(N)
return tdt
MOVEFILE:
/* Moves files (removes leading drive in dest. file) */
/* NOTES: */
/* - This routine is (currently) limited to moving files around on the */
/* SAME drive! */
/* - This routine does NOT check to see if destination file already */
/* exists. */
arg origmovefile, destmovefile
destmovefile=filespec("P",destmovefile)""filespec("N",destmovefile)
"move "origmovefile" "destmovefile" > nul"
return
OLDFILE:
/* returns file number of days old */
/* WARNING: This routine is NO GOOD after 2069! */
arg oldfilespec
/* starting at third char, dom indicates days in year for previous months */
dom=" 000031059090121151182212243274304335"
oldfiledate=stream(oldfilespec,"C","Query datetime")
month=left(oldfiledate,2)
day=substr(oldfiledate,4,2)
year=substr(oldfiledate,7,2)
/* file date stamps don't include centuries, so assume that if less than */
/* 70, then add 100 (file years are 1970-2069) */
if year<70 then
year=100+year
fileday=693959+((year-1)*365)+((year-1)%4)-((year-1)%100)+((year-1)%400)+((month>2)&(year//4=0))-(year//100=0)+(year//400=0)+(substr(dom,month*3,3))+day
return date("B")-fileday
/* */
/* fileday construction (uses same rules as REXX's date("B") function): */
/* */
/* 693959 days to 1900 */
/* + ((year-1)*365) previous year X days/year */
/* + ((year-1)%4) every 4th, leap year */
/* - ((year-1)%100) every 100th, non-leap year */
/* + ((year-1)%400) every 400th, leap year */
/* + ((month>2)&(year//4=0)) if 4th and greater than Feb, leap year */
/* - (year//100=0) if cent, this is NON leap year */
/* + (year//400=0) if 4th cent, this is leap year */
/* + (substr(dom,month*3,3)) days in previous months */
/* + day day number */
OPENAPPEND:
arg openappendfile
openappendtest=stream(openappendfile,"Command","Open write")
if left(openappendtest,5)<>"READY" then
return 0
else do
openappendtest=stream(openappendfile,"Command","Seek < 0")
return 1
end
OPENREAD:
arg openreadfile
openreadtest=stream(openreadfile,"Command","Open read")
if left(openreadtest,5)<>"READY" then
return 0
else
return 1