Created
August 2, 2024 20:43
-
-
Save ftoledo/aa62ef4965c11023feb9cddcc2907cbf to your computer and use it in GitHub Desktop.
Revisions
-
ftoledo created this gist
Aug 2, 2024 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,313 @@ #!/usr/bin/env python2 import glob import os.path import stat import sys from datetime import datetime #-------------------------------------------------------------------------- def IsoTime(t): return datetime.fromtimestamp(int(t)).strftime('%Y-%m-%d %H:%M:%S') #-------------------------------------------------------------------------- class OBFile: flavours = { 'f':"Normal", 'i':"Immediate", 'c':"Continuous", 'd':"Direct", 'h':"Hold", 'o':"Normal" } def __init__(self, path, zone, net=-1, node=-1): self.fullpath = os.path.abspath(path) self.zone = zone self.net = net self.node = node self.point = 0 self.txt = "" self.type = "unk" self.refs = [] try: st = os.stat(path) self.mtime = st.st_mtime self.size = st.st_size self.isDir = stat.S_ISDIR(st.st_mode) self.fname = os.path.basename(path) self.root, self.ext = os.path.splitext(self.fname) self.ext = self.ext[1:].lower() if len(self.root) == 8: if self.net < 0: self.net = int(self.root[:4], 16) if self.node < 0: self.node = int(self.root[4:], 16) else: self.point = int(self.root[4:], 16) self.nn = str(self.zone) + ':' + str(self.net) + '/' + str(self.node) if self.point > 0: self.nn += '.' + str(self.point) if self.ext == "try": tfile = open(path) tfile.seek(5) self.txt = "Try result: " + tfile.readline().strip() tfile.close() self.type = "try" elif self.ext == "bsy" or self.ext == "csy": self.txt = "" self.type = "bsy" elif self.ext == "hld": self.txt = "Holding until: " + IsoTime(open(path).readline()) self.type = "hld" elif self.ext == "req": self.txt = "" self.type = "req" elif self.ext[1:] == "ut" and self.ext[0] in "oicdh": self.txt = "Flavour: " + self.flavours[self.ext[0]] self.type = "out" elif self.ext[1:] == "lo" and self.ext[0] in "ficdh": self.txt = "Flavour: " + self.flavours[self.ext[0]] self.type = "flo" elif self.ext == "pnt" and self.isDir: self.txt = "Point directory" self.type = "pnt" self.obdir = OutBoundDir(path, 5, self.zone, self.net, self.node) except ValueError: self.txt = "" self.type = "err" # The following directives are documented as a standard: # # "#" - Indicates that the files should be truncated to zero- # length after successfully sending the file to the remote # system. This is normally only employed when sending compressed # mail (archived mail) to the remote. # # "^" - delete the file after successfully sending the file to # the remote system. # # "~" - skip the line from treatment. It may be useful to mark # an already processed line. # # <none> - indicates that the file should be sent and neither be # truncated nor deleted after sending. Listing the file with the # full path circumvents problems with files that have a name # starting with a character that is a known directive. # # # Software may optionally recognise the following directives: # # "-" As an alternate for "^" # # "!" As an alternate for "~" # # "@" Send file, do not truncate or delete. def OrphansToRefs(self, orphans, fname, flochar): for i, obfile in reversed(list(enumerate(orphans))): if obfile.FileName() == fname: obfile.flochar = flochar self.refs.append(obfile) del orphans[i] break def HandleLine(self, line, orphans): if line[0] in "#^~-!@": flochar = line[0] fpath = line[1:].strip() else: flochar = ' ' fpath = line.strip() fname = os.path.basename(fpath) self.OrphansToRefs(orphans, fname, flochar) def GetRefFiles(self, orphans): if self.type == "flo": tfile = open(self.fullpath) for line in tfile: self.HandleLine(line, orphans) tfile.close() def NodeNumber(self): return self.nn if hasattr(self, 'nn') else '' def FileName(self): return self.fname if hasattr(self, 'fname') else '' def KnownType(self): return hasattr(self, 'type') and self.type != "unk" and self.type != "err" def Size(self): return " <dir>" if self.isDir else "%7d" % (self.size, ) def FileInfoStr(self): return "%-12s - %s - %s" % (self.fname, IsoTime(self.mtime), self.Size()) def Print(self, indent): print (' ' * indent), '+', self.FileInfoStr(), '-', self.txt for obfile in self.refs: obfile.PrintRef(indent) if hasattr(self, 'obdir'): self.obdir.PrintFiles() def FloActionTxt(self): if self.flochar == '#': return "Truncate after send" elif self.flochar == '^' or self.flochar == '-': return "Delete after send" elif self.flochar == '!' or self.flochar == '~': return "Skip" else: return "Keep after send" def PrintRef(self, indent): print (' ' * indent), self.flochar, self.FileInfoStr(), "- Action:", self.FloActionTxt() def PrintOrphan(self, indent): print (' ' * (indent + 2)), self.FileInfoStr() #-------------------------------------------------------------------------- class OutBoundDir: def __init__(self, oDir, indent, zone, net=-1, node=-1): self.oDir = oDir self.zone = zone self.net = net self.node = node self.indent = indent self.nfiles = {} self.orphans = [] self.AddFiles(glob.glob(os.path.join(oDir, "*"))) def AddFiles(self, files): if files: self.FilesToLists(files) self.orphans.sort(key=OBFile.FileName) self.AddOrphansToFloFiles() def FilesToLists(self, files): for oFile in files: obf = OBFile(oFile, self.zone, self.net, self.node) if obf.KnownType(): self.AddFile(obf) else: self.orphans += obf, def AddFile(self, obfile): if obfile.nn not in self.nfiles: self.nfiles[obfile.nn] = [] self.nfiles[obfile.nn] += obfile, def AddOrphansToFloFiles(self): for key, obfiles in self.nfiles.iteritems(): for obfile in obfiles: obfile.GetRefFiles(self.orphans) def PrintNodes(self): for key in sorted(self.nfiles): print (' ' * self.indent) + key for obfile in self.nfiles[key]: obfile.Print(self.indent) def PrintOrphans(self): if self.orphans: print (' ' * self.indent) + "Orphaned files:" for orphan in self.orphans: orphan.PrintOrphan(self.indent) def PrintFiles(self): self.PrintNodes() self.PrintOrphans() def NodeStrs(self): if self.net >= 0: return "Node", str(self.zone) + ':' + str(self.net) + '/' + str(self.node if self.node >= 0 else 0) else: return "Zone", str(self.zone) def PrintHeader(self): print self.oDir, "- %s %s" % self.NodeStrs() print def Print(self): self.PrintHeader() self.PrintFiles() print """ Netmail: .?ut Referemce: .?lo "#" - truncate "^" "-" - delete "~" "!" - skip the line from treatment. It may be useful to mark an already processed line. <none> "@" Send file, do not truncate or delete file request: .req flavours: i - Immediate c - Continuous d - Direct h - Hold o/f - Normal (Netmail/Reference) Immediate ("iut" or "ilo") Continuous ("cut" or "clo") Direct ("dut" or "dlo") Normal ("out" or "flo") Hold ("hut" or "hlo") bsy (busy) control file csy (call) control file For information purposes a [bc]sy file may contain one line of PID information (less than 70 characters). hld (hold) control file A hld file must contain a one line string with the expiration of the hold period expressed in UNIX-time. try control file A try file must contain one line string with a diagnostic message. It is for information purposes only. For information purposes the second line of a try file may contain one line of PID information. ( < 70 characters) """ #-------------------------------------------------------------------------- class OutBoundDirs: def __init__(self, outbound, defzone): self.outbound = outbound self.defzone = defzone def Handle(self): if not os.path.isdir(self.outbound): print "Error:", self.outbound, "is not a dir." return 1 self.outboundDirs = [ (self.outbound, self.defzone), ] self.GetOutboundDirs() self.ProcessOutboundDirs() return 0 def GetOutboundDirs(self): dirs = glob.glob(self.outbound + ".*") dirs.sort() self.outboundStrLen = len(self.outbound) + 1 for dir in dirs: self.GetOutboundDir(dir) def GetOutboundDir(self, dir): ext = dir[self.outboundStrLen:] try: zone = int(ext, 16) self.outboundDirs += ((dir, zone),) except ValueError: pass def ProcessOutboundDirs(self): for od in self.outboundDirs: obd = OutBoundDir(od[0], 2, od[1]) obd.Print() #-------------------------------------------------------------------------- if __name__ == "__main__": rv = 0 print "bsostatus 1.1.0 Copyright (C) 2022-01-17 by Wilfred van Velzen" print if len(sys.argv) < 3: print "usage:", sys.argv[0], "<default outbound dir> <default zone>" rv = 1 else: rv = OutBoundDirs(sys.argv[1], int(sys.argv[2])).Handle() sys.exit(rv)