diff options
-rw-r--r-- | CHANGELOG | 2 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | TODO | 6 | ||||
-rwxr-xr-x | archivemail.py | 58 | ||||
-rwxr-xr-x | setup.py | 2 | ||||
-rwxr-xr-x | test_archivemail.py | 69 |
6 files changed, 126 insertions, 13 deletions
@@ -4,6 +4,8 @@ Version 0.4.5 - 28 April 2002 an mbox mailbox you would get a python error. * Added a lot more testing to test_archivemail.py (test_archivemail.py is now 37% bigger than archivemail -- scary) + * Added a new '--size' option which allows you to only archive messages + over a certain size. Version 0.4.4 - 27 April 2002 * Fixed a bug where the long --suffix option was not working (although the @@ -1,5 +1,5 @@ -VERSION=0.4.4 +VERSION=0.4.5 VERSION_TAG=v$(subst .,_,$(VERSION)) TARFILE=archivemail-$(VERSION).tar.gz @@ -1,16 +1,14 @@ -Goals for next minor release (0.4.5): +Goals for next minor release (0.4.6): ------------------------------------- * Think about the best way to specify the names of archives created with possibly an --archive-name option. -* Add a lot more tests (see top of test_archivemail.py) +* Add more tests (see top of test_archivemail.py) * We need some better checking to see if we are really looking at a valid mbox-format mailbox. Goals for next major release (0.5.0): ------------------------------------- -* Add a --size option to only archive messages greater than a certain byte - size. * Lock any original .gz files - is this necessary? * Check for symlink attacks for tempfiles (although we don't use /var/tmp) diff --git a/archivemail.py b/archivemail.py index 846e9b0..182d43a 100755 --- a/archivemail.py +++ b/archivemail.py @@ -22,7 +22,7 @@ Website: http://archivemail.sourceforge.net/ """ # global administrivia -__version__ = "archivemail v0.4.4" +__version__ = "archivemail v0.4.5" __cvs_id__ = "$Id$" __copyright__ = """Copyright (C) 2002 Paul Rodger <paul@paulrodger.com> This is free software; see the source for copying conditions. There is NO @@ -147,6 +147,7 @@ class Options: quiet = 0 read_buffer_size = 8192 script_name = os.path.basename(sys.argv[0]) + min_size = None verbose = 0 warn_duplicates = 0 @@ -162,11 +163,11 @@ class Options: """ try: - opts, args = getopt.getopt(args, '?D:Vd:hno:qs:uv', + opts, args = getopt.getopt(args, '?D:S:Vd:hno:qs:uv', ["date=", "days=", "delete", "dry-run", "help", - "include-flagged", "no-compress", "output-dir=", - "preserve-unread", "quiet", "suffix=", "verbose", - "version", "warn-duplicate"]) + "include-flagged", "no-compress", "output-dir=", + "preserve-unread", "quiet", "size=", "suffix=", + "verbose", "version", "warn-duplicate"]) except getopt.error, msg: user_error(msg) @@ -202,6 +203,8 @@ class Options: self.quiet = 1 if o in ('-s', '--suffix'): self.archive_suffix = a + if o in ('-S', '--size'): + self.min_size = string.atoi(a) if o in ('-u', '--preserve-unread'): self.preserve_unread = 1 if o in ('-v', '--verbose'): @@ -224,9 +227,11 @@ class Options: unexpected_error(("output directory is world-writable: " + \ "%s -- I feel nervous!") % self.output_dir) if self.days_old_max < 1: - user_error("argument to -d must be greater than zero") + user_error("--days argument must be greater than zero") if self.days_old_max >= 10000: - user_error("argument to -d must be less than 10000") + user_error("--days argument must be less than 10000") + if self.min_size is not None and self.min_size < 1: + user_error("--size argument must be greater than zero") if self.quiet and self.verbose: user_error("you cannot use both the --quiet and --verbose options") @@ -563,6 +568,7 @@ Options are as follows: -D, --date=DATE archive messages older than DATE -o, --output-dir=DIR directory to store archives (default: same as original) -s, --suffix=NAME suffix for archive filename (default: '%s') + -S, --size=NUM only archive messages NUM bytes or larger -n, --dry-run don't write to anything - just show what would be done -u, --preserve-unread never archive unread messages --delete delete rather than archive old mail (use with caution!) @@ -780,6 +786,42 @@ def is_unread(message): return 1 +def is_smaller(message, size): + """Return true if the message is smaller than size bytes, false otherwise""" + assert(message) + assert(size > 0) + file_name = None + message_size = None + try: + file_name = message.fp.name + except AttributeError: + pass + if file_name: + # with maildir and MH mailboxes, we can just use the file size + message_size = os.path.getsize(file_name) + else: + # with mbox mailboxes, not so easy + message_size = 0 + if message.unixfrom: + message_size = message_size + len(message.unixfrom) + for header in message.headers: + message_size = message_size + len(header) + message_size = message_size + 1 # the blank line after the headers + start_offset = message.fp.tell() + message.fp.seek(0, 2) # seek to the end of the message + end_offset = message.fp.tell() + message.rewindbody() + message_size = message_size + (end_offset - start_offset) + if message_size < size: + vprint("message is too small (%d bytes), minimum bytes : %d" % \ + (message_size, size)) + return 1 + else: + vprint("message is not too small (%d bytes), minimum bytes: %d" % \ + (message_size, size)) + return 0 + + def should_archive(message): """Return true if we should archive the message, false otherwise""" old = 0 @@ -795,6 +837,8 @@ def should_archive(message): return 0 if not options.include_flagged and is_flagged(message): return 0 + if options.min_size and is_smaller(message, options.min_size): + return 0 if options.preserve_unread and is_unread(message): return 0 return 1 @@ -19,7 +19,7 @@ check_python_version() # define & run this early - 'distutils.core' is new from distutils.core import setup setup(name="archivemail", - version="0.4.4", + version="0.4.5", description="archive and compress old email", license="GNU GPL", url="http://archivemail.sourceforge.net/", diff --git a/test_archivemail.py b/test_archivemail.py index 3f7119e..18d6f4f 100755 --- a/test_archivemail.py +++ b/test_archivemail.py @@ -1216,6 +1216,75 @@ class TestArchiveMboxUncompressed(unittest.TestCase): os.remove(name) +class TestArchiveSize(unittest.TestCase): + """check that the 'size' argument works""" + def testSmaller(self): + """giving a size argument smaller than the message""" + for execute in ("package", "system_long", "system_short"): + self.mbox_name = make_mbox(messages=1, hours_old=(24 * 181)) + size_arg = os.path.getsize(self.mbox_name) - 1 + self.copy_name = tempfile.mktemp() + shutil.copyfile(self.mbox_name, self.copy_name) + if execute == "package": + archivemail.options.quiet = 1 + archivemail.options.min_size = size_arg + archivemail.archive(self.mbox_name) + elif execute == "system_long": + run = "./archivemail.py --size=%d --quiet %s" % \ + (size_arg, self.mbox_name) + self.assertEqual(os.system(run), 0) + elif execute == "system_short": + run = "./archivemail.py -S%d --quiet %s" % \ + (size_arg, self.mbox_name) + self.assertEqual(os.system(run), 0) + else: + sys.exit(1) + assert(os.path.exists(self.mbox_name)) + self.assertEqual(os.path.getsize(self.mbox_name), 0) + archive_name = self.mbox_name + "_archive.gz" + assert(os.path.exists(archive_name)) + self.assertEqual(os.system("gzip -d %s" % archive_name), 0) + archive_name = self.mbox_name + "_archive" + assert(os.path.exists(archive_name)) + assert(filecmp.cmp(archive_name, self.copy_name, shallow=0)) + self.tearDown() + + def testBigger(self): + """giving a size argument bigger than the message""" + for execute in ("package", "system_long", "system_short"): + self.mbox_name = make_mbox(messages=1, hours_old=(24 * 181)) + size_arg = os.path.getsize(self.mbox_name) + 1 + self.copy_name = tempfile.mktemp() + shutil.copyfile(self.mbox_name, self.copy_name) + if execute == "package": + archivemail.options.quiet = 1 + archivemail.options.min_size = size_arg + archivemail.archive(self.mbox_name) + elif execute == "system_long": + run = "./archivemail.py --size=%d --quiet %s" % \ + (size_arg, self.mbox_name) + self.assertEqual(os.system(run), 0) + elif execute == "system_short": + run = "./archivemail.py -S%d --quiet %s" % \ + (size_arg, self.mbox_name) + self.assertEqual(os.system(run), 0) + else: + sys.exit(1) + assert(os.path.exists(self.mbox_name)) + assert(filecmp.cmp(self.mbox_name, self.copy_name, shallow=0)) + archive_name = self.mbox_name + "_archive.gz" + assert(not os.path.exists(archive_name)) + self.tearDown() + + def tearDown(self): + archivemail.options.quiet = 0 + archivemail.options.min_size = None + archive = self.mbox_name + "_archive" + for name in (self.mbox_name, self.copy_name, archive, archive + ".gz"): + if name and os.path.exists(name): + os.remove(name) + + class TestArchiveMboxMode(unittest.TestCase): """file mode (permissions) of the original mbox should be preserved""" def testOld(self): |