[Add a simple inter-process locking abstraction. Daniel Burrows **20051009030705] [Add a configuration parser that supports the general layout of what I need without getting too specific. Daniel Burrows **20051009060044] [Allow extra config files to be read into the system after the fact, and allow an empty configuration to be initialized to start with. Daniel Burrows **20051009060509] [Rename ConfigFile to Config. Daniel Burrows **20051009060547 Since it's really a repository of configuration information and doesn't correspond directly to a file (obviously, since several files can be read into one Config object), this makes much more sense. ] [Refer to self.defaults, not defaults, when fetching values. Daniel Burrows **20051010191115] [Allow quoted strings as identities in addition to regexps (the strings are matched literally). Daniel Burrows **20051010194252] [Add code to relay a message to a remote SMTP server. Daniel Burrows **20051010194732] [Use an NFS-safe locking protocol, at the cost of possibly leaving stale locks around. :-/ Daniel Burrows **20051010202954] [Add GPL boilerplate to lock.py Daniel Burrows **20051010203332] [Add GPL boilerplate to config.py. Daniel Burrows **20051010203605] [Add GPL boilerplate to relay.py Daniel Burrows **20051010203631] [Always delete the temporary filename after locking a file. Daniel Burrows **20051010212435] [Only delete the lockfile once for a given Lock object. Daniel Burrows **20051010212909] [Remove some unnecessary exception-catching. Daniel Burrows **20051010212952] [Use a 'finally' clause to simplify the lock creation protocol. Daniel Burrows **20051010213629] [Don't set the filename to a non-None value until the lock was successfully taken. Daniel Burrows **20051010213740 Without this change, the lockfile would get deleted by __del__ after a failed attempt to lock it! ] [Add an abstraction around a reasonably safe message queue. Daniel Burrows **20051010220524] [Add an accessor to check whether a queue is locked. Daniel Burrows **20051010221349] [Switch to a protocol where individual messages are locked for delivery. Daniel Burrows **20051011000011] [Remove the intrinsic locking from the queue; since you now lock individual messages, it's not necessary. Daniel Burrows **20051011000115] [Always use an absolute path when storing the queue directory's name. Daniel Burrows **20051011012038] [Don't parse messages while iterating over the queue; just return bare filenames. Daniel Burrows **20051011012411] [Add a routine to the queue that delivers a single message. Daniel Burrows **20051011012603] [Create a leafsmtp package and move the backend modules into it. Daniel Burrows **20051011013303] [Let the caller of relay() choose how to prompt the user for a password. Daniel Burrows **20051011013517] [Add support in relay() for delivery to local addresses using an MDA. Daniel Burrows **20051011023921] [Fix a silly typo in __init__.py's documentation. Daniel Burrows **20051011024114] [Move the queue's deliver() and delivery_lock() routines into a QueuedMessage object; return that object when iterating over the queue. Daniel Burrows **20051011024252] [Let callers of deliver() pass the lock in, as an alternative to acquiring it in the method. Daniel Burrows **20051011030022] [Add support for delivery-locking a message *before* inserting it into the queue. Daniel Burrows **20051011030113] [Add a module which can be used to access the standard configuration of the leafsmtp system. Daniel Burrows **20051011033725] [Use emailUtils.getaddress() to parse address lists. Daniel Burrows **20051011040124] [Sanity-check against missing recipient addresses. Daniel Burrows **20051011040240] [Expect the list of recipients as an argument, rather than guessing it from the message. Daniel Burrows **20051011040623 This was added to support how sendmail historically worked and what mail clients expect. ] [Freeze the recipient addresses when a message is placed into the queue, so they're available for a later delivery. Daniel Burrows **20051011045917] [Move the QueuedMessage class to the top-level of the leafsmtp module. Daniel Burrows **20051011051220] [Return the newly queued message from the enqueue() routine along with the lock. Daniel Burrows **20051011053020] [Add a missing import of the queue module. Daniel Burrows **20051011053519] [Trim some excess arguments to deliver_unqualified (oops). Daniel Burrows **20051011053746] [Print debugging information about the MDA delivery if debug_smtp is True. Daniel Burrows **20051011054057] [Fix the order of arguments to configenv.get_value when looking up the MDA. Daniel Burrows **20051011054503] [A pipe's close() returns None if nothing was wrong; check for that before trying to inspect it as a return value from a subprocess. Daniel Burrows **20051011055150] [Don't try to use the SMTP server to relay unqualified addresses. (oops) Daniel Burrows **20051011055626] [Add a basic "driver" file that works as a proto-replacement for /usr/lib/sendmail. Daniel Burrows **20051011060356] [Only use local delivery for unqualified addresses, not all destination addresses! Daniel Burrows **20051011060609] [Fix a keywork argument (with_lock => withlock) Daniel Burrows **20051011062045] [Add a read-accessor for the filename used in a lock. Daniel Burrows **20051011062143] [Fix the sanity-check when delivering a message with an existing lock. Daniel Burrows **20051011062406] [Make the output queue format match the input queue format. Daniel Burrows **20051011062435] [Load up an existing queue if *either* enqueue_messages or defer_delivery is set. Daniel Burrows **20051011062715] [Print nicer messages from errors encountered while enqueuing deferred messages. Daniel Burrows **20051011062742] [Whoops: iterate over the message queue object, not the 'queue' module. Daniel Burrows **20051011062830] [Remove old debug code that snuck into the repository. Daniel Burrows **20051011062931] [Use argv[0] to figure out where the modules might be. Daniel Burrows **20051011162313] [Actually set the envelope from using the -f command-line parameter. Daniel Burrows **20051011162737] [Use time.time() to generate unique filenames in the queue, not time.clock(). Daniel Burrows **20051011164557 time.time() is the time since the Unix epoch, while time.clock() is the time since the current process started. ] [Also use time.time() to generate temporary lock files. Daniel Burrows **20051011164658] [Safe an open file object pointing at the lockfile, and use fstat instead of stat to check if the link(2) succeeded. Daniel Burrows **20051011165121] [Use fstat instead of stat when inserting messages into the queue; handle zero link counts. Daniel Burrows **20051011165312] [Do a sanity-check on the lock file before deleting it, and blank it out (closing it) when the lock is released. Daniel Burrows **20051011165753] [Explicitly call the lock a DotLock. Daniel Burrows **20051011190812] [Switch to a "file plus name" locking scheme, make DotLock a subclass of Lock, and modify the queue to handle these changes. Daniel Burrows **20051011193730] [Add an abstraction for fcntl locks, using a similar interface to DotLock. Daniel Burrows **20051011200619] [Fix the generation of an error messagee. Daniel Burrows **20051011200650 Exceptions are converted to strings using the builtin str() function, not a non-existant str() method. ] [Allow users of FcntlLock to access the file pointer representing the lock. Daniel Burrows **20051011203158] [Open FcntlLock files for both reading and writing. Daniel Burrows **20051011205415] [Add the missing self argument to get_filename. Daniel Burrows **20051011205458] [Add the missing self argument to get_lockname. Daniel Burrows **20051011205513] [Implement get_locked_fp for DotLock. Daniel Burrows **20051011205521] [Modify the queue data structures to support choosing between dot-locks and fcntl-locks at runtime. Daniel Burrows **20051011205647] [Add a default value for the "lock_protocol" option. Daniel Burrows **20051011210029] [Move the code that grabs a delivery_lock in deliver() outside of the try...finally block; if the delivery lock fails, there's no need to release it. Daniel Burrows **20051011210040] [Generate better error messages for badly formed queue files. Daniel Burrows **20051011210519] [Be less whitespace-sensitive when checking for blank lines. Daniel Burrows **20051011210617] [Add a big fat warning that you should call seek() on the result of get_locked_fp(). Daniel Burrows **20051011210855] [Call seek() on the locked file pointer in the delivery routine. Daniel Burrows **20051011210925] [Add a not-entirely-necessary call to fp.seek in enqueue(). Daniel Burrows **20051011211006] [Update the idle question about locking protocols. Daniel Burrows **20051011211646] [Cleanly handle the case of a missing From header. Daniel Burrows **20051011213154] [Set From from the envelope_from if the From header is missing. Daniel Burrows **20051011214202] [Use lock_protocol to choose how messages are locked. Daniel Burrows **20051011214307] [Add support for a legacy sendmail option (which apparently mailx passes by default). Daniel Burrows **20051011220831] [Add support for seting options from the command-line, while ignoring old sendmail options that use the same option prefix. Daniel Burrows **20051011222535] [Create a function to perform a queue run. Daniel Burrows **20051011223212] [Force a filesystem sync of message files after we write them, as a hedge against crashes and other badness. Daniel Burrows **20051011231544] [Update the documentation of the config module to indicate that quoted strings are accepted after "identity". Daniel Burrows **20051012000837] [Escape the TO address when delivering unqualified mail, to avoid a theoretical future attack. Daniel Burrows **20051012003415] [Add a basic README file. Daniel Burrows **20051012004051] [Use the version number to generate a --version command-line option. Daniel Burrows **20051012011610] [Note the version number in the README. Daniel Burrows **20051012011647] [Make the documentation clearer and add example configurations. Daniel Burrows **20051012055432] [Convert SMTP exceptions using str(), not .str(). Daniel Burrows **20051012055720] [Expect either an OSError or an IOError when piping to an MDA. Daniel Burrows **20051012154025] [Create a LockError exception class, for use when a lock cannot be acquired. Daniel Burrows **20051012155330] [Catch LockError in addition to the other error types when a lock cannot be acquired. Daniel Burrows **20051012155513] [Throw LockError instead of unpredictable exceptions when a lock can't be acquired. Daniel Burrows **20051012155735] [Fix the docstrings of the queue to reflect where LockErrors get thrown. Daniel Burrows **20051012155900] [Fork into the background when doing a queue run if background_delivery is set, so the queue run goes in parallel too. Daniel Burrows **20051012160211] [Add configuration items to control the number of permitted simultaneous deliveries. Daniel Burrows **20051012162429] [Correct an unbound variable reference in the 'unable to unlink message' error. Daniel Burrows **20051012162510] [Only catch OSErrors when unlinking message files, and display them in the warning message. Daniel Burrows **20051012162552] [Use the throttling configuration items to throttle simultaneous deliveries using a very simple locking protocol. Daniel Burrows **20051012162807] [Document the throttling configuration items. Daniel Burrows **20051012163110] [Substitute for $USER and $LOGNAME when delivering. Daniel Burrows **20051012163235] [Document the autosubstitution behavior. Daniel Burrows **20051012163304] [Don't open fntl locks for appending; I hope this fixes a weird bug where messages would be written twice to the same file. Daniel Burrows **20051012165529] [Include the textual description of terrors in the "can't unlink message" warning. Daniel Burrows **20051013180459] [Since Python buffers files internally, we need to flush changes to disk prior to releasing file locks (so other processes see all of our writes). Daniel Burrows **20051013230036] [Remember that some locks go away when you fork; to be safe, unconditionally reacquire the lock after forking into the background. Daniel Burrows **20051014163442] [Don't leave droppings behind: if an error occurs while enqueuing a message, delete any partial message. Daniel Burrows **20051014163903 This is safe, since if an error did occur at this step, we always generate an error message and exit abnormally (in which case the caller should not consider the message successfully sent). ] [Close stdout/stdin after forking to the background in a queue run. Daniel Burrows **20051014164921] [If it's expected that a message might be locked, print the message indicating that it is to stdout, not stderr. Daniel Burrows **20051014164938 Among other things, this means it's automatically suppressed when the program is forked into the background. ] [Call the list of TO addresses 'to_addrs' instead of 'args'. Daniel Burrows **20051217214137] [Implement a -t option that, like the corresponding option in sendmail, scans the To, Cc, and Bcc headers for additional recipients. Daniel Burrows **20051217214214] [Add support for a list of messages whose delivery is pending; this will be used to eliminate the "one process per message delivery" rule. Daniel Burrows **20060720014402] [Add a docstring to the QueuedMessage class. Daniel Burrows **20060720014505] [Clean up the docstring for the Queue class. Daniel Burrows **20060720014529] [Add a "null" lock type that disables locking (useful for, eg, representing optional locks that weren't taken). Daniel Burrows **20060720150444] [Sanity-check for empty recipient lists up-front. Daniel Burrows **20060720151833] [Move throttle handling into the main program; this is needed since in the future, each throttled delivery process will actually check the pending list for more messages to deliver before terminating. Daniel Burrows **20060720151859] [Add a new exception class QueueError for fatal errors in queue handling. Daniel Burrows **20060720152255] [Catch QueueError along with other fatal message errors from the main program. Daniel Burrows **20060720152328] [Use lock.LockError for unknown locking modes instead of ValueError. Daniel Burrows **20060720152350] [Make is_valid_message_name a method of PendingMessages, so it can verify that the named file actually exists in the queue, and be stricter about what filenames are allowed in (this avoids problems where os.stat would barf on syntactically invalid filenames). Daniel Burrows **20060721005137] [Remove a reference to the delivery lock (that we no longer take). Daniel Burrows **20060721005444] [Add support for blocking locks to the lock module (blocking with a dotlock is a bit broken right now). Daniel Burrows **20060721144317] [When wrapping pending messages into the list, make sure to join the message filename with the queue filename (otherwise it creates a message in the current directory!) Daniel Burrows **20060722002958] [Fix a silly bug in __getitem__ for PendingMessages: slice is a global function; the local parameter indicating which slice we're accessing is called "key". Daniel Burrows **20060722005706] [Use a function, not a property, to retrieve the current pending list (to make it clearer that you get a fresh one each time), and add convenience functions that handle the locking semantics of the pending list transparently. Daniel Burrows **20060722005756] [Write a function to repeatedly deliver pending messages on a queue until none are left. Daniel Burrows **20060722005838] [Apparently global variables no longer show up automatically in local scopes; explicitly import options in queue_run. Daniel Burrows **20060722010041] [Rewrite the toplevel driver to store new messages to be delivered in the pending list and to read from the pending list after delivering (while holding its delivery lock). Daniel Burrows **20060722010333] [Don't truncate the pending file when we open it with an fcntl lock; should fix the problems with writing new entries into them. Daniel Burrows **20060725014035] [Tighten up the "safe path" regex (don't allow unsafe chars in the first character!) Daniel Burrows **20060725014423] [Add a helpful comment. Daniel Burrows **20060725014517] [Create queued messages with mode 0600, not something random. Daniel Burrows **20060725014524] [Complain loudly if the caller passes an invalid message name into PendingMessage.append(). Daniel Burrows **20060725014708] [Whoops...turns out that os.open takes the mode as an optional parameter but not as a keyword parameter, despite what pydoc says. Daniel Burrows **20060725143350] [Always use blocking semantics by default when opening the pending list. Daniel Burrows **20060729190411] [Add a first cut at a "manager" that can examine the current queue and send messages from it. Currently it's only partly functional. Daniel Burrows **20061028135452] [When generating the set of pending messages, make sure to map messages to their filenames. This lets us correctly set the "pending" flag in the UI. Daniel Burrows **20061028142854] [Read the leafsmtp configuration when the manager starts up. Daniel Burrows **20061028150535] [Clean up how widgets are fetched from the Glade XML object, to make it simpler to retrieve new ones without cutting-and-pasting. Daniel Burrows **20061028150554] [Only read the headers when initially parsing a message file; delay reading the message itself until the "msg" property is fetched (will allow scanning the directory without getting bogged down by huge messages). Daniel Burrows **20061028150813] [Put the date into the message list as its string representation. Daniel Burrows **20061028151437] [Sort the message list by message timestamp (secondary sort on filename). Daniel Burrows **20061028151459] [Add messageinfo objects as the last column in their rows. Daniel Burrows **20061028152049] [Actually, the right place to ensure a full ordering of list-entries is when we set the file_bindings property. Move the sort function there (replacing the old, insufficient one). Daniel Burrows **20061028152614] [Add constants to the main window object giving the column index of each sub-value of a message row. Daniel Burrows **20061028160025] [Use a merge algorithm to update the tree (this lets us do a bulk update without clearing the whole tree and re-building it). Daniel Burrows **20061028160054] [Create a "refresh" button that re-loads the current directory state. This should go away in the future, but will be useful for testing in the near future. Daniel Burrows **20061028161006] [Load in a default set of substitution variables on startup. Daniel Burrows **20061028161620] [Expose the queued message associated with a list entry as "qm". Daniel Burrows **20061028170658] [Abstract loading the .glade file into a __get_xml function. Daniel Burrows **20061028170737] [Fix the do_update method. Daniel Burrows **20061028170859] [Write code to send the currently selected message and hook it up to the appropriate toolbar button. Daniel Burrows **20061028170951] [Give the "quit" handler a more expected name, and write it. Daniel Burrows **20061028171455] [Allow multiple objects to be selected in the list view. Daniel Burrows **20061028171732] [Add a todo list for must-have features. Daniel Burrows **20061028181430] [Add a status-bar to the main window that shows the current number of messages in the queue. Daniel Burrows **20061029195423] [Add support for viewing messages that are stuck in the message queue. Daniel Burrows **20061029195526] [Move get_widget to the top of the file with get_xml. Daniel Burrows **20061029195534] [Remove the extra scrolled-window that somehow got wrapped around the main manager window. Daniel Burrows **20061029195611] [Add simple timeout-based polling of the message queue. Daniel Burrows **20061029200526] [Fix viewing messages (forgot to propagate the visible-header-set to sub-invocations of add_message_to_buffer). Daniel Burrows **20061029201958] [Add support for deleting messages from the queue. Daniel Burrows **20061029202936] [Update the queue display appropriately when one or more messages are removed from the end of the list. Daniel Burrows **20061029203350] [Fix a typo in the deletion error handling code. Daniel Burrows **20061030135413] [When a message is deleted from the queue, destroy any open window that is showing it. Daniel Burrows **20061030150248] [Store a backpointer to the MessageInfo object associated with each MessageWin. Daniel Burrows **20061030151658] [Make __do_update into a public method do_update. Daniel Burrows **20061030151810] [Make the global name of the main window "mainwin". Daniel Burrows **20061030151832] [MessageWin now stores the subject and sender of its message as properties on itself. Daniel Burrows **20061030151904] [Make the "delete" button in a MessageWin delete the associated message, destroy the GTK window, and run a global update (a bit hacky?) Daniel Burrows **20061030152039] [Use the correct fully qualified name for MessageError. Daniel Burrows **20061031015453] [Add support for sending a message from its viewer window. The code is a bit ugly but works. Daniel Burrows **20061031015509] [Take the timezone into account when parsing dates for display in the manager window and for sorting messages. Daniel Burrows **20061031020509] [Use stderr instead of stdout to write error messages. Daniel Burrows **20070509035728] [Add HOSTNAME as a configuration variable. Daniel Burrows **20070512194525] [Read the default queue from the configuration file. Daniel Burrows **20070706020727] [Adjust the default width/height of the main window. Daniel Burrows **20070706021132] [Fix running the manager from other directories. Daniel Burrows **20070706021317]