1.1 --- a/imiptools/__init__.py Sat Oct 14 19:11:58 2017 +0200
1.2 +++ b/imiptools/__init__.py Sat Oct 14 23:15:16 2017 +0200
1.3 @@ -36,9 +36,13 @@
1.4 # Processing of incoming messages.
1.5
1.6 def get_all_values(msg, key):
1.7 +
1.8 + "Return all values in 'msg' for 'key'."
1.9 +
1.10 l = []
1.11 for v in msg.get_all(key) or []:
1.12 - l += [s.strip() for s in v.split(",")]
1.13 + for s in v.split(","):
1.14 + l.append(s.strip())
1.15 return l
1.16
1.17 class Processor:
1.18 @@ -127,90 +131,25 @@
1.19 given 'stream'.
1.20 """
1.21
1.22 - # Obtain the different kinds of recipients plus sender address.
1.23 -
1.24 - original_recipients = []
1.25 - recipients = []
1.26 - senders = []
1.27 - lmtp = []
1.28 - store_type = []
1.29 - store_dir = []
1.30 - publishing_dir = []
1.31 - preferences_dir = []
1.32 - journal_dir = []
1.33 - local_smtp = False
1.34 -
1.35 - l = []
1.36 -
1.37 - for arg in args:
1.38 -
1.39 - # Switch to collecting recipients.
1.40 -
1.41 - if arg == "-o":
1.42 - l = original_recipients
1.43 -
1.44 - # Switch to collecting senders.
1.45 -
1.46 - elif arg == "-s":
1.47 - l = senders
1.48 -
1.49 - # Switch to getting the LMTP socket.
1.50 -
1.51 - elif arg == "-l":
1.52 - l = lmtp
1.53 -
1.54 - # Detect sending to local users via SMTP.
1.55 + args = parse_args(args, {"--show-config" : ("show_config", False)})
1.56
1.57 - elif arg == "-L":
1.58 - local_smtp = True
1.59 -
1.60 - # Switch to getting the store type.
1.61 -
1.62 - elif arg == "-T":
1.63 - l = store_type
1.64 -
1.65 - # Switch to getting the store directory.
1.66 -
1.67 - elif arg == "-S":
1.68 - l = store_dir
1.69 -
1.70 - # Switch to getting the publishing directory.
1.71 -
1.72 - elif arg == "-P":
1.73 - l = publishing_dir
1.74 -
1.75 - # Switch to getting the preferences directory.
1.76 -
1.77 - elif arg == "-p":
1.78 - l = preferences_dir
1.79 -
1.80 - # Switch to getting the journal directory.
1.81 -
1.82 - elif arg == "-j":
1.83 - l = journal_dir
1.84 -
1.85 - # Ignore debugging options.
1.86 -
1.87 - elif arg == "-d":
1.88 - self.debug = True
1.89 - else:
1.90 - l.append(arg)
1.91 -
1.92 - getvalue = lambda value, default=None: value and value[0] or default
1.93 -
1.94 - self.messenger = Messenger(lmtp_socket=getvalue(lmtp), local_smtp=local_smtp, sender=getvalue(senders))
1.95 + self.debug = args["debug"]
1.96
1.97 # Obtain arguments or configured defaults.
1.98
1.99 - self.store_type = getvalue(store_type, settings["STORE_TYPE"])
1.100 - self.store_dir = getvalue(store_dir, settings["STORE_DIR"])
1.101 - self.journal_dir = getvalue(journal_dir, settings["JOURNAL_DIR"])
1.102 - self.preferences_dir = getvalue(preferences_dir, settings["PREFERENCES_DIR"])
1.103 - self.publishing_dir = getvalue(publishing_dir, settings["PUBLISH_DIR"])
1.104 + self.store_type = args.get("store_type") or settings["STORE_TYPE"]
1.105 + self.store_dir = args.get("store_dir") or settings["STORE_DIR"]
1.106 + self.journal_dir = args.get("journal_dir") or settings["JOURNAL_DIR"]
1.107 + self.preferences_dir = args.get("preferences_dir") or settings["PREFERENCES_DIR"]
1.108 + self.publishing_dir = args.get("publishing_dir") or settings["PUBLISH_DIR"]
1.109 +
1.110 + self.messenger = Messenger(lmtp_socket=args["lmtp"],
1.111 + local_smtp=args["local_smtp"],
1.112 + sender=(args["senders"] or [None])[0])
1.113
1.114 # Show configuration and exit if requested.
1.115
1.116 - if "--show-config" in args:
1.117 + if args["show_config"]:
1.118 print """\
1.119 Store type: %s
1.120 Store directory: %s
1.121 @@ -229,7 +168,7 @@
1.122
1.123 # Process the input.
1.124
1.125 - self.process(stream, original_recipients)
1.126 + self.process(stream, args["original_recipients"])
1.127
1.128 def __call__(self):
1.129
1.130 @@ -240,54 +179,18 @@
1.131
1.132 args = sys.argv[1:]
1.133
1.134 - if "--help" in args:
1.135 - print >>sys.stderr, """\
1.136 -Usage: %s [ -o <recipient> ... ] [-s <sender> ... ] [ -l <socket> | -L ] \\
1.137 - [ -T <store type ] \\
1.138 - [ -S <store directory> ] [ -P <publishing directory> ] \\
1.139 - [ -p <preferences directory> ] [ -j <journal directory> ] \\
1.140 - [ -d ] [ --show-config ]
1.141 -
1.142 -Address options:
1.143 -
1.144 --o Indicate the original recipients of the message, overriding any found in
1.145 - the message headers
1.146 --s Indicate the senders of the message, overriding any found in the message
1.147 - headers
1.148 -
1.149 -Delivery options:
1.150 -
1.151 --l The socket filename for LMTP communication with a mailbox solution,
1.152 - selecting the LMTP delivery method
1.153 --L Selects the local SMTP delivery method, requiring a suitable mail system
1.154 - configuration
1.155 + # Show the help text if requested.
1.156
1.157 -(Where a program needs to deliver messages, one of the above options must be
1.158 -specified.)
1.159 -
1.160 -Configuration options (overriding configured defaults):
1.161 -
1.162 --j Indicates the location of quota-related journal information
1.163 --P Indicates the location of published free/busy resources
1.164 --p Indicates the location of user preference directories
1.165 --S Indicates the location of the calendar data store containing user storage
1.166 - directories
1.167 --T Indicates the store and journal type (the configured value if omitted)
1.168 + if "--help" in args:
1.169 + show_help(os.path.split(sys.argv[0])[-1])
1.170
1.171 -Output options:
1.172 -
1.173 --d Run in debug mode, producing informative output describing the behaviour
1.174 - of the program, displaying responses on standard output instead of sending
1.175 - messages
1.176 -
1.177 -Diagnostic options:
1.178 -
1.179 ---show-config Show the configuration with the specified options and exit
1.180 - without performing any actions
1.181 -""" % os.path.split(sys.argv[0])[-1]
1.182 + # In debug mode, process the message without exception handling.
1.183
1.184 elif "-d" in args:
1.185 self.process_args(args, sys.stdin)
1.186 +
1.187 + # Otherwise, process the message and handle exceptions gracefully.
1.188 +
1.189 else:
1.190 try:
1.191 self.process_args(args, sys.stdin)
1.192 @@ -465,4 +368,118 @@
1.193 else:
1.194 return False
1.195
1.196 +# Standard arguments used by imip-agent programs.
1.197 +
1.198 +def parse_args(args, extra_argdefs=None):
1.199 +
1.200 + """
1.201 + Interpret the given program arguments 'args'. Any 'extra_argdefs' define a
1.202 + mapping from option arguments to (option name, starting value) tuples to be
1.203 + considered in addition to (or as replacements for) the default definitions.
1.204 + """
1.205 +
1.206 + argdefs = {
1.207 + "-d" : ("debug", False),
1.208 + "-j" : ("journal_dir", None),
1.209 + "-l" : ("lmtp", None),
1.210 + "-L" : ("local_smtp", False),
1.211 + "-o" : ("original_recipients", []),
1.212 + "-p" : ("preferences_dir", None),
1.213 + "-P" : ("publishing_dir", None),
1.214 + "-s" : ("senders", []),
1.215 + "-S" : ("store_dir", None),
1.216 + "-T" : ("store_type", None),
1.217 + }
1.218 +
1.219 + argdefs.update(extra_argdefs)
1.220 +
1.221 + l = []
1.222 + option = None
1.223 +
1.224 + for arg in args:
1.225 +
1.226 + # Set any selected option value.
1.227 +
1.228 + if option and argdefs.has_key(option):
1.229 + name, value = argdefs[option]
1.230 + argdefs[option] = name, arg
1.231 + option = None
1.232 +
1.233 + # Where recognised, obtain the option name and value.
1.234 +
1.235 + elif argdefs.has_key(arg):
1.236 + name, value = argdefs[arg]
1.237 +
1.238 + # For boolean options, invert the current value.
1.239 +
1.240 + if isinstance(value, bool):
1.241 + argdefs[arg] = name, not value
1.242 +
1.243 + # For list options, switch to the given list and collect arguments.
1.244 +
1.245 + elif isinstance(value, list):
1.246 + l = value
1.247 +
1.248 + # Otherwise, select the option.
1.249 +
1.250 + else:
1.251 + option = arg
1.252 +
1.253 + # Where unrecognised, collect the argument in the current list.
1.254 +
1.255 + else:
1.256 + l.append(arg)
1.257 +
1.258 + # Return a mapping from option names to values.
1.259 +
1.260 + return dict(argdefs.values())
1.261 +
1.262 +def show_help(progname):
1.263 + print >>sys.stderr, help_text % progname
1.264 +
1.265 +help_text = """\
1.266 +Usage: %s [ -o <recipient> ... ] [-s <sender> ... ] [ -l <socket> | -L ] \\
1.267 + [ -T <store type ] \\
1.268 + [ -S <store directory> ] [ -P <publishing directory> ] \\
1.269 + [ -p <preferences directory> ] [ -j <journal directory> ] \\
1.270 + [ -d ] [ --show-config ]
1.271 +
1.272 +Address options:
1.273 +
1.274 +-o Indicate the original recipients of the message, overriding any found in
1.275 + the message headers
1.276 +-s Indicate the senders of the message, overriding any found in the message
1.277 + headers
1.278 +
1.279 +Delivery options:
1.280 +
1.281 +-l The socket filename for LMTP communication with a mailbox solution,
1.282 + selecting the LMTP delivery method
1.283 +-L Selects the local SMTP delivery method, requiring a suitable mail system
1.284 + configuration
1.285 +
1.286 +(Where a program needs to deliver messages, one of the above options must be
1.287 +specified.)
1.288 +
1.289 +Configuration options (overriding configured defaults):
1.290 +
1.291 +-j Indicates the location of quota-related journal information
1.292 +-P Indicates the location of published free/busy resources
1.293 +-p Indicates the location of user preference directories
1.294 +-S Indicates the location of the calendar data store containing user storage
1.295 + directories
1.296 +-T Indicates the store and journal type (the configured value if omitted)
1.297 +
1.298 +Output options:
1.299 +
1.300 +-d Run in debug mode, producing informative output describing the behaviour
1.301 + of the program, displaying responses on standard output instead of sending
1.302 + messages
1.303 +
1.304 +Diagnostic options:
1.305 +
1.306 +--show-config Show the configuration with the specified options and exit
1.307 + without performing any actions
1.308 +"""
1.309 +
1.310 # vim: tabstop=4 expandtab shiftwidth=4