aboutsummaryrefslogtreecommitdiffstats
path: root/archive_folder.py
diff options
context:
space:
mode:
Diffstat (limited to 'archive_folder.py')
-rwxr-xr-xarchive_folder.py221
1 files changed, 221 insertions, 0 deletions
diff --git a/archive_folder.py b/archive_folder.py
new file mode 100755
index 0000000..7859bea
--- /dev/null
+++ b/archive_folder.py
@@ -0,0 +1,221 @@
+#!/usr/bin/env python3.6
+# note http://docs.python.org/lib/module-doctest.html
+# resp. file:///usr/share/doc/python-docs-*/html/lib/module-doctest.html
+# FIXME
+# read https://www.toptal.com/python/an-introduction-to-mocking-in-python
+# & https://blog.fugue.co/2016-02-11-python-mocking-101.html
+# for unittest.mock tutorials
+# for testing
+import argparse
+import configparser
+import email
+import logging
+import os
+import sys
+from datetime import date
+
+logging.basicConfig(format='%(levelname)s:%(funcName)s:%(message)s',
+ stream=sys.stdout, level=logging.DEBUG)
+log = logging.getLogger('imapArch')
+
+# from java.util import Properties, Date
+# from java.lang import System
+# from javax.mail import *
+# from jarray import array
+
+
+class FolderNotFoundError(IOError):
+ pass
+
+
+def __getMessageDate(msg):
+ """
+ Return the date of the message
+
+ @param msg analyzed message
+ @return GregorianCalendar of the messages date
+ @throws MessagingException
+ """
+ dateMS = msg.getReceivedDate().getTime() // 1000
+ dateStruct = date.fromtimestamp(dateMS)
+ return dateStruct
+
+
+class ArchivableFolder(list):
+
+ def __init__(self, source, year):
+ """
+ Constructor for the folder.
+
+ @param source folder from the messages should be archived
+ @param year int of the year for which the messages are
+ archived
+ """
+ self.sourceFolder = source
+ targetName = self.__getArchiveFolderName(source.getFullName(), year)
+ self.targetFolder = self.sourceFolder.getFolder(targetName)
+
+ def __getArchiveFolderName(self, srcFldName, year):
+ """
+ @param folder string with the folder name
+ @param year int
+ @return
+ """
+ archFolder = "INBOX/Archiv/"
+ rootLen = len("INBOX/")
+ if not(srcFldName[:rootLen] == "/INBOX/"):
+ raise FolderNotFoundError(
+ "We expect all folders to be under INBOX folder.")
+ baseName = srcFldName[rootLen:]
+ archFolder = "/" + archFolder + year + "/" + baseName
+ return archFolder
+
+ def add(self, msg):
+ self.append(msg)
+
+ def doArchive(self):
+ for message in self:
+ log.debug("Moving %s from %s to %s.",
+ message, self.sourceFolder.getFullName(),
+ self.targetFolder.getFullName())
+ # self.sourceFolder.copyMessages(array(self, Message),
+ # self.targetFolder)
+ # for message in self:
+ # message.setFlag(Flags.Flag.DELETED, true)
+ # self.sourceFolder.expunge()
+
+
+class Archives(dict):
+ """Collects archivable folders indexed by tuple of
+ folderName and year
+ """
+
+ def __init__(self):
+ pass
+
+ def add(self, msg):
+ """
+ Check whether the ArchivableFolder (@see ArchivableFolder)
+ for the particular year actually exists, and if not then create
+ it. In any event add
+ @param msg
+ """
+ fld = msg.getFolder()
+ msgDate = __getMessageDate(msg)
+ year = msgDate.year
+
+ if not(self.search(fld, year)):
+ archfld = ArchivableFolder(fld, year)
+ self[self.__createKey(fld, year)] = archfld
+
+ def __createKey(self, name, year):
+ """
+ Create a key for the list
+ @param fldName String with the full name of the folder
+ @param year int of the year of the messages to be stored
+ there
+ @return tuple consisting from the both parameters of
+ this function.
+ """
+ return(name, year)
+
+ def search(self, fld, year):
+ """
+ Find out whether the object with the key consisting of
+ the folder name and year exists in this object.
+
+ @param fld Folder where the message is stored
+ @param year int year of the message date
+ @return boolean saying whether the folder for this message
+ has been already added to this object.
+ """
+ key = self.__createKey(fld.getFullName(), year)
+ return key in self
+
+ def archive(self):
+ for key in self:
+ self.doArchive()
+
+
+class ArchivedStore(object):
+
+ def __init__(self, serverKey=None):
+ config = configparser.ConfigParser()
+ config.read(os.path.expanduser('~/.config/imap_archiver.cfg'))
+ acc_name = serverKey if serverKey is not None \
+ else config['general']['account']
+ self.cfg = dict(config.items(acc_name))
+ # if debug:
+ # self.session.setDebug(True)
+ # try:
+ # self.store = self.session.getStore("imaps")
+ # except:
+ # print >> sys.stderr, "Cannot get Store"
+ # raise
+
+ self._threeMonthAgo = date.today()
+ newmonth = self._threeMonthAgo.month - 3
+ self._threeMonthAgo = self._threeMonthAgo.replace(month=newmonth)
+
+ log.debug("host = %s, user = %s, password = %s",
+ self.cfg['host'], self.cfg['username'],
+ self.cfg['password'])
+
+ self.__login(host, user, password)
+
+ def __login(self, server, user, password):
+ try:
+ self.store.connect(server, user, password)
+ except:
+ log.debug("Cannot connect to %s as %s with password %s",
+ server, user, password)
+ raise
+
+ def archive(self, from_folder, archive_base):
+ # type: (str, str) -> None
+ inboxfolder = self.store.getDefaultFolder().getFolder("INBOX")
+ folderList = inboxfolder.list('*')
+
+ for folder in folderList:
+ if folder.getFullName()[:len("INBOX/Archiv")] != "INBOX/Archiv":
+ archMsgsCnt = self.__archiveFolder(folder)
+ # folder.close(False)
+ print("Processed messages = %d" % archMsgsCnt)
+
+ def __archiveFolder(self, fld):
+ fld.open(Folder.READ_WRITE)
+ for msg in fld.getMessages():
+ msgDate = __getMessageDate(msg)
+ print >>sys.stderr, str(msgDate), str(self._threeMonthAgo)
+ if msgDate < self._threeMonthAgo:
+ archFolder = self.__getArchiveFolderName(msg)
+# print >> sys.stderr, archFolder
+# fld.copyMessages(array([msg],type(msg)), archFolder)
+# msg.setFlag(Flags.Flag.DELETED, true)
+ print("%s -> %s : %s" % (fld.getFullName(),
+ archFolder.getFullName(), msgDate))
+ folderLen = len(fld.getMessages())
+ fld.close(False)
+ return(folderLen)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self):
+ pass # FIXME self.something.close()
+
+
+if __name__ == '__main__':
+ argp = argparse.ArgumentParser()
+ argp.add_argument('-d',
+ help='How old messages we should keep')
+ argp.add_argument('server',
+ help='Symbolic name of the server to be used')
+ argp.add_argument('folder',
+ help='Folder which should be archived')
+ argp.add_argument('archive',
+ help='Root folder to store annual archives to')
+ args = argp.parse_args()
+
+ with ArchivedStore(args.server) as myStore:
+ myStore.archive(args.folder, args.archive)