summaryrefslogtreecommitdiff
path: root/alot/db.py
diff options
context:
space:
mode:
authorpazz <patricktotzke@gmail.com>2011-07-23 18:50:54 +0100
committerpazz <patricktotzke@gmail.com>2011-07-23 18:50:54 +0100
commit23f4e2307a77f8ae43f47ef3f1e0ed686371dd6f (patch)
tree290b22bcbca54ff701a89db679064655dcdcdab1 /alot/db.py
parent475b65bde3ee4a331676a8ac8ebbd2f91d049e22 (diff)
separated Message from db
since Message also includes mime-handler calling ist doesn't really fit anymore
Diffstat (limited to 'alot/db.py')
-rw-r--r--alot/db.py227
1 files changed, 10 insertions, 217 deletions
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 <patricktotzke@gmail.com>
"""
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()