From 23f4e2307a77f8ae43f47ef3f1e0ed686371dd6f Mon Sep 17 00:00:00 2001 From: pazz Date: Sat, 23 Jul 2011 18:50:54 +0100 Subject: separated Message from db since Message also includes mime-handler calling ist doesn't really fit anymore --- alot/db.py | 227 +++---------------------------------------------------------- 1 file changed, 10 insertions(+), 217 deletions(-) (limited to 'alot/db.py') diff --git a/alot/db.py b/alot/db.py index a6aaac22..a6ccb4fc 100644 --- a/alot/db.py +++ b/alot/db.py @@ -18,18 +18,11 @@ Copyright (C) 2011 Patrick Totzke """ from notmuch import Database, NotmuchError from datetime import datetime -import email from collections import deque -import os -import logging -import tempfile -from settings import config -from settings import get_mime_handler -import helper -from helper import cmd_output +from message import Message -DB_ENC = 'utf8' +DB_ENC = 'utf-8' class DatabaseError(Exception): @@ -96,7 +89,8 @@ class DBManager: sync_maildir_flags=sync) msg.thaw() - def tag(self, querystring, tags, remove_rest=False, sync_maildir_flags=False): + def tag(self, querystring, tags, remove_rest=False, + sync_maildir_flags=False): """ add tags to all matching messages. Raises :exc:`DatabaseROError` if in read only mode. @@ -112,9 +106,11 @@ class DBManager: if self.ro: raise DatabaseROError() if remove_rest: - self.writequeue.append(('set', querystring, tags, sync_maildir_flags)) + self.writequeue.append(('set', querystring, tags, + sync_maildir_flags)) else: - self.writequeue.append(('tag', querystring, tags, sync_maildir_flags)) + self.writequeue.append(('tag', querystring, tags, + sync_maildir_flags)) def untag(self, querystring, tags, sync_maildir_flags=False): """ @@ -129,7 +125,8 @@ class DBManager: """ if self.ro: raise DatabaseROError() - self.writequeue.append(('untag', querystring, tags, sync_maildir_flags)) + self.writequeue.append(('untag', querystring, tags, + sync_maildir_flags)) def count_messages(self, querystring): """returns number of messages that match querystring""" @@ -181,12 +178,10 @@ class Thread: if not thread: query = self._dbman.query('thread:' + self._id) thread = query.search_threads().next() - logging.debug(thread) self._total_messages = thread.get_total_messages() self._authors = str(thread.get_authors()).decode(DB_ENC) self._subject = str(thread.get_subject()).decode(DB_ENC) ts = thread.get_oldest_date() - logging.debug(ts) self._oldest_date = datetime.fromtimestamp(ts) self._newest_date = datetime.fromtimestamp(thread.get_newest_date()) self._tags = set(thread.get_tags()) @@ -302,205 +297,3 @@ class Thread: def get_total_messages(self): """returns number of contained messages""" return self._total_messages - - -class Message: - def __init__(self, dbman, msg, thread=None): - """ - :param dbman: db manager that is used for further lookups - :type dbman: alot.db.DBManager - :param msg: the wrapped message - :type msg: notmuch.database.Message - :param thread: this messages thread - :type thread: alot.db.thread - """ - self._dbman = dbman - self._id = msg.get_message_id() - self._thread_id = msg.get_thread_id() - self._thread = thread - self._datetime = datetime.fromtimestamp(msg.get_date()) - self._filename = msg.get_filename() - # TODO: change api to return unicode - self._from = msg.get_header('From').decode(DB_ENC) - self._email = None # will be read upon first use - self._attachments = None # will be read upon first use - self._tags = set(msg.get_tags()) - - def __str__(self): - """prettyprint the message""" - aname, aaddress = self.get_author() - if not aname: - aname = aaddress - #tags = ','.join(self.get_tags()) - return "%s (%s)" % (aname, self.get_datestring()) - - def __hash__(self): - """Implement hash(), so we can use Message() sets""" - return hash(self._id) - - def __cmp__(self, other): - """Implement cmp(), so we can compare Message()s""" - res = cmp(self.get_message_id(), other.get_message_id()) - return res - - def get_email(self): - """returns email.Message representing this message""" - if not self._email: - f_mail = open(self.get_filename()) - self._email = email.message_from_file(f_mail) - f_mail.close() - return self._email - - def get_date(self): - """returns date as datetime obj""" - return self._datetime - - def get_filename(self): - """returns absolute path of messages location""" - return self._filename - - def get_message_id(self): - """returns messages id (a string)""" - return self._id - - def get_thread_id(self): - """returns id of messages thread (a string)""" - return self._thread_id - - def get_message_parts(self): - """returns a list of all body parts of this message""" - out = [] - for msg in self.get_email().walk(): - if not msg.is_multipart(): - out.append(msg) - return out - - def get_tags(self): - """returns tags attached to this message as list of strings""" - return list(self._tags) - - def get_thread(self): - """returns the thread this msg belongs to as alot.db.Thread object""" - if not self._thread: - self._thread = self._dbman.get_thread(self._thread_id) - return self._thread - - def get_replies(self): - """returns a list of replies to this msg""" - t = self.get_thread() - return t.get_replies_to(self) - - def get_datestring(self, pretty=True): - """returns formated datestring in sup-style, eg: 'Yest.3pm'""" - return helper.pretty_datetime(self._datetime) - - def get_author(self): - """returns realname and address pair of this messages author""" - return email.Utils.parseaddr(self._from) - - def add_tags(self, tags): - """adds tags to message - - :param tags: tags to add - :type tags: list of str - """ - self._dbman.tag('id:' + self._id, tags) - self._tags = self._tags.union(tags) - - def remove_tags(self, tags): - """remove tags from message - - :param tags: tags to remove - :type tags: list of str - """ - self._dbman.untag('id:' + self._id, tags) - self._tags = self._tags.difference(tags) - - def get_attachments(self): - if not self._attachments: - self._attachments = [] - for part in self.get_message_parts(): - if part.get_content_maintype() != 'text': - self._attachments.append(Attachment(part)) - return self._attachments - - def accumulate_body(self): - bodytxt = '' - for part in self.get_email().walk(): - ctype = part.get_content_type() - enc = part.get_content_charset() - raw_payload = part.get_payload(decode=True) - if part.get_content_maintype() == 'text': - if enc: - raw_payload = unicode(raw_payload, enc) - else: - raw_payload = unicode(raw_payload, errors='replace') - if ctype == 'text/plain': - bodytxt += raw_payload - else: - #get mime handler - handler = get_mime_handler(ctype, key='view', - interactive=False) - if handler: - #open tempfile. Not all handlers accept stuff from stdin - tmpfile = tempfile.NamedTemporaryFile(delete=False, - suffix='.html') - #write payload to tmpfile - if part.get_content_maintype() == 'text': - tmpfile.write(raw_payload.encode('utf8')) - else: - tmpfile.write(raw_payload) - #create and call external command - cmd = handler % tmpfile.name - rendered_payload = cmd_output(cmd) - #remove tempfile - tmpfile.close() - os.unlink(tmpfile.name) - if rendered_payload: # handler had output - bodytxt += unicode(rendered_payload.strip(), - encoding='utf8', errors='replace') - elif part.get_content_maintype() == 'text': - bodytxt += raw_payload - # else drop - return bodytxt - - -class Attachment: - """represents a single mail attachment""" - - def __init__(self, emailpart): - """ - :param emailpart: a non-multipart email that is the attachment - :type emailpart: email.message.Message - """ - self.part = emailpart - - def __str__(self): - return '%s:%s (%s)' % (self.get_content_type(), - self.get_filename(), - self.get_size()) - - def get_filename(self): - """return the filename, extracted from content-disposition header""" - return self.part.get_filename() - - def get_content_type(self): - """mime type of the attachment""" - return self.part.get_content_type() - - def get_size(self): - """returns attachments size as human-readable string""" - size_in_kbyte = len(self.part.get_payload()) / 1024 - if size_in_kbyte > 1024: - return "%.1fM" % (size_in_kbyte / 1024.0) - else: - return "%dK" % size_in_kbyte - - def save(self, path): - """save the attachment to disk. Uses self.get_filename - in case path is a directory""" - if os.path.isdir(path): - path = os.path.join(path, self.get_filename()) - FILE = open(path, "w") - FILE.write(self.part.get_payload(decode=True)) - FILE.close() -- cgit v1.2.3