aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xarchive_folder.py18
-rwxr-xr-ximapArchive.py215
-rwxr-xr-xlistFolders.py54
-rwxr-xr-xplayWithImap.py67
4 files changed, 16 insertions, 338 deletions
diff --git a/archive_folder.py b/archive_folder.py
index 4b86707..3d52918 100755
--- a/archive_folder.py
+++ b/archive_folder.py
@@ -31,6 +31,7 @@ class MessageError(IOError):
Capas = collections.namedtuple('Capas', ['MOVE', 'UIDPLUS'])
SEP_RE = re.compile(r'\s+"([/.])"\s+')
+FOLDER_RE = re.compile(r'\s+"[/.]"\s+')
class Message(object):
@@ -231,6 +232,14 @@ class EmailServer(object):
dir = Folder(self.box, arch_dir, create=True)
# dir.move_messages(msg_ids)
+ def list_folders(self):
+ ok, data = self.box.list()
+ if ok != 'OK':
+ raise IOError('Cannot list folders!')
+
+ return sorted([FOLDER_RE.split(x.decode())[1] for x in data],
+ key=str.lower)
+
def __enter__(self):
return self
@@ -244,11 +253,12 @@ if __name__ == '__main__':
locale.setlocale(locale.LC_ALL, 'en_US')
argp = argparse.ArgumentParser()
subps = argp.add_subparsers(dest='cmd')
- subp_list = subps.add_parser('servers', help='List available servers (by keywords)')
+ subp_servers = subps.add_parser('servers', help='List available servers (by keywords)')
+ subp_list = subps.add_parser('list', help='List all folders')
subp_arc = subps.add_parser('archive', help='Archive folder[s]')
subp_arc.add_argument('-d', type=int, default=14, dest='days',
help='How old messages we should keep')
- subp_arc.add_argument('-s', '--server', default='localhost',
+ subp_arc.add_argument('-s', '--server',
help='Symbolic name of the server to be used')
subp_arc.add_argument('folder', help='Folder which should be archived')
subp_arc.add_argument('archive', help='Root folder to store annual archives to')
@@ -259,6 +269,10 @@ if __name__ == '__main__':
config = EmailServer.get_config()
sects = set(config.keys()) - {'DEFAULT', 'general'}
print('Available servers:\n%s' % tuple(sects))
+ elif args.cmd == 'list':
+ myStore = EmailServer()
+ folders = myStore.list_folders()
+ print('\n'.join(folders))
else:
before = date.today() - timedelta(days=args.days)
with EmailServer(args.server, args.archive) as myStore:
diff --git a/imapArchive.py b/imapArchive.py
deleted file mode 100755
index 2354342..0000000
--- a/imapArchive.py
+++ /dev/null
@@ -1,215 +0,0 @@
-#!/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
-# FIXME TODO FIXME DON'T DO THIS! Active Work is on archive_folder
-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):
- """
- TODO Make Archive store into context manager.
- """
-
- 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):
- 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)
-
-if __name__ == '__main__':
- argp = argparse.ArgumentParser()
- 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() as myStore:
- myStore.archive()
diff --git a/listFolders.py b/listFolders.py
deleted file mode 100755
index 741ae41..0000000
--- a/listFolders.py
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/usr/bin/env python3.6
-
-import configparser
-import logging
-import os.path
-
-import imaplib
-
-logging.basicConfig(format='%(levelname)s:%(funcName)s:%(message)s',
- level=logging.DEBUG)
-log = logging.getLogger('listFolders')
-
-def list_folder(name, wildcards='*'):
- ok, data = box.list(name, wildcards)
- if ok != 'OK':
- raise ServerError('Cannot list folder %s' % name)
- return data[0]
-
-def get_separator():
- data = list_folder('pumpa')
-
- log.debug('data = %s (%s)', data, type(data))
-
- if data is None:
- data = list_folder('""', '""')
-
- data = data.decode().split(' ')
- if len(data) == 3:
- return data[1].strip(' "')
- else:
- raise ServerError('Cannot find folder separator from %s' % data)
-
-config = configparser.ConfigParser()
-config.read(os.path.expanduser('~/.config/imap_archiver.cfg'))
-acc_name = config['general']['account']
-cfg = dict(config.items(acc_name))
-
-box = imaplib.IMAP4_SSL(host=cfg['host'])
-ok, data = box.login(cfg['username'], cfg['password'])
-if ok != 'OK':
- raise IOError('Cannot login with credentials %s' % str(cfg))
-
-sep = get_separator()
-print('sep = %s' % sep)
-# data = list_folder('""', '""')
-# log.debug('data = %s', data)
-# sep = data.split()[1].decode()
-#
-# data = list_folder('Work/punk')
-# log.debug('ok = %s, data = %s (type %s)', ok, data, type(data))
-
-# for fld in data:
-# spl_fld = fld.decode().split(sep)
-# print(spl_fld[1].strip())
diff --git a/playWithImap.py b/playWithImap.py
deleted file mode 100755
index dd68fb6..0000000
--- a/playWithImap.py
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/usr/bin/env python3.6
-
-import configparser
-import os.path
-
-import imapy
-
-config = configparser.ConfigParser()
-config.read(os.path.expanduser('~/.config/imap_archiver.cfg'))
-cfg = dict(config.items(config['general']['account']))
-print(cfg)
-
-
-# my $msg;
-#
-# my $imap = Mail::IMAPClient->new();
-# $imap = Mail::IMAPClient->new(
-# Server => "localhost",
-# User => "matej",
-# Password => "lubdkc",
-# UID => 1
-# ) or die "Cannot connect to localhost as matej: $@";
-#
-# $imap->select('INBOX');
-# my $hash = $imap->fetch_hash("RFC822.SIZE","INTERNALDATE","FLAGS","ENVELOPE");
-# #print Data::Dumper->Dumpxs([$hash],['$hash']);
-#
-# #print "\n===============================\n";
-# my @folders = $imap->folders;
-# #print join("\n",@folders),".\n";
-#
-# #print "\n===============================\n";
-# # or s/folders/subscribed/
-# @folders = $imap->folders("INBOX" . $imap->separator . "Pratele" . $imap->separator);
-# print join("\n",@folders),".\n";
-#
-# print "\n===============================\n";
-# my $msgID;
-# my $headers;
-# foreach $msg (keys(%$hash)) {
-# $msgID = $imap->get_header($msg,"Message-Id");
-# print "\$msg ID = $msg\nMESSAGE-ID = $msgID\n";
-# $headers = $imap->parse_headers($msg,"Date","Received","Subject","To");
-# print "Headers = " . Data::Dumper->Dumpxs([$headers],['$headers']) . "\n";
-# }
-#
-# ## Get a list of messages in the current folder:
-# #my @msgs = $imap->messages or die "Could not messages: $@\n";
-# ## Get a reference to an array of messages in the current folder:
-# #my $msgs = $imap->messages or die "Could not messages: $@\n";
-#
-# #use Mail::IMAPClient;
-# # my $imap = Mail::IMAPClient->new( Server => $imaphost,
-# # User => $login,
-# # Password=> $pass,
-# # Uid => 1, # optional
-# # );
-# #
-# # $imap->select("World Domination");
-# # # get the flags for every message in my 'World Domination' folder
-# # $flaghash = $imap->flags( scalar($imap->search("ALL"))) ;
-# #
-# # # pump through sorted hash keys to print results:
-# # for my $k (sort { $flaghash->{$a} <=> $flaghash->{$b} } keys %$flaghash) {
-# # # print: Message 1: \Flag1, \Flag2, \Flag3
-# # print "Message $k:\t",join(", ",@{$flaghash->{$k}}),"\n";
-# # }