2 from ctypes import c_int, c_char_p, c_void_p
3 from cnotmuch.globals import nmlib, STATUS, NotmuchError
6 class Database(object):
7 """ Wrapper around a notmuch_database_t
9 Do note that as soon as we tear down this object, all derived queries,
10 threads, and messages will be freed as well.
17 """Class attribute of users default database"""
19 """notmuch_database_get_path (notmuch_database_t *database)"""
20 _get_path = nmlib.notmuch_database_get_path
21 _get_path.restype = c_char_p
23 """notmuch_database_open (const char *path, notmuch_database_mode_t mode)"""
24 _open = nmlib.notmuch_database_open
25 _open.restype = c_void_p
27 """ notmuch_database_find_message """
28 _find_message = nmlib.notmuch_database_find_message
29 _find_message.restype = c_void_p
31 """notmuch_database_get_all_tags (notmuch_database_t *database)"""
32 _get_all_tags = nmlib.notmuch_database_get_all_tags
33 _get_all_tags.restype = c_void_p
35 """ notmuch_database_create(const char *path):"""
36 _create = nmlib.notmuch_database_create
37 _create.restype = c_void_p
39 def __init__(self, path=None, create=False, status= MODE_READ_ONLY):
40 """ Open or create a notmuch database
42 If path is None, we will try to read a users notmuch configuration and
43 use his default database.
44 Throws a NotmuchError in case of failure.
48 # no path specified. use a user's default database
49 if Database._std_db_path is None:
50 #the following line throws a NotmuchError if it fails
51 Database._std_db_path = self._get_user_default_db()
52 path = Database._std_db_path
55 self.open(path, status)
57 self.create(path, status)
59 def create(self, path, status=MODE_READ_ONLY):
60 """ notmuch_database_create(const char *path)
62 :returns: Raises :exc:`notmuch.NotmuchError` in case
63 of any failure (after printing an error message on stderr).
65 res = Database._create(path, status)
69 message="Could not create the specified database")
72 def open(self, path, status= MODE_READ_ONLY):
73 """calls notmuch_database_open
75 :returns: Raises :exc:`notmuch.NotmuchError` in case
76 of any failure (after printing an error message on stderr).
78 res = Database._open(path, status)
82 message="Could not open the specified database")
86 """notmuch_database_get_path (notmuch_database_t *database); """
87 return Database._get_path(self._db)
89 def find_message(self, msgid):
90 """notmuch_database_find_message
91 :param msgid: The message id
94 :returns: Message() or None if no message is found or if an
95 out-of-memory situation occurs.
98 raise NotmuchError(STATUS.NOT_INITIALIZED)
99 msg_p = Database._find_message(self._db, msgid)
102 return Message(msg_p, self)
104 def get_all_tags(self):
105 """Return a Tags() object (list of all tags found in the database)
107 :returns: Tags() object or raises :exc:`NotmuchError` with
108 STATUS.NULL_POINTER on error
111 raise NotmuchError(STATUS.NOT_INITIALIZED)
113 tags_p = Database._get_all_tags (self._db)
115 raise NotmuchError(STATUS.NULL_POINTER)
116 return Tags(tags_p, self)
119 return "'Notmuch DB " + self.get_path() + "'"
122 """Close and free the notmuch database if needed"""
123 if self._db is not None:
124 print("Freeing the database now")
125 nmlib.notmuch_database_close(self._db)
127 def _get_user_default_db(self):
128 """ Reads a user's notmuch config and returns his db location
130 Throws a NotmuchError if it cannot find it"""
131 from ConfigParser import SafeConfigParser
133 config = SafeConfigParser()
134 config.read(os.path.expanduser('~/.notmuch-config'))
135 if not config.has_option('database','path'):
136 raise NotmuchError(message=
137 "No DB path specified and no user default found")
138 return config.get('database','path')
142 """Returns a pointer to the current notmuch_database_t or None"""
146 #------------------------------------------------------------------------------
148 """Wrapper around notmuch_tags_t"""
149 class notmuch_tags_t(ctypes.Structure):
150 """the opaque tags struct that is returned by functions."""
154 _get = nmlib.notmuch_tags_get
155 _get.restype = c_char_p
157 def __init__(self, tags_p, db=None):
159 msg_p is a pointer to an notmuch_message_t Structure. If it is None,
160 we will raise an NotmuchError(STATUS.NULL_POINTER).
162 Is passed the db these tags are derived from, and saves a
163 reference to it, so we can automatically delete the db object
164 once all derived objects are dead.
166 Tags() provides an iterator over all contained tags. However, you will
167 only be able to iterate over the Tags once, because the underlying C
168 function only allows iterating once.
169 #TODO: make the iterator work more than once and cache the tags in
173 NotmuchError(STATUS.NULL_POINTER)
177 print "Inited Tags derived from %s" %(str(db))
180 """ Make Tags an iterator """
184 if self._tags is None:
186 nmlib.notmuch_tags_move_to_next(self._tags)
187 if not nmlib.notmuch_tags_valid(self._tags):
188 print("Freeing the Tags now")
189 nmlib.notmuch_tags_destroy (self._tags)
191 return Tags._get (self._tags)
194 """Close and free the notmuch tags"""
195 if self._tags is not None:
196 print("Freeing the Tags now")
197 nmlib.notmuch_tags_destroy (self._tags)
199 #------------------------------------------------------------------------------
200 class Message(object):
201 """Wrapper around notmuch_message_t"""
203 """notmuch_message_get_filename (notmuch_message_t *message)"""
204 _get_filename = nmlib.notmuch_message_get_filename
205 _get_filename.restype = c_char_p
206 """notmuch_message_get_message_id (notmuch_message_t *message)"""
207 _get_message_id = nmlib.notmuch_message_get_message_id
208 _get_message_id.restype = c_char_p
210 """notmuch_message_get_tags (notmuch_message_t *message)"""
211 _get_tags = nmlib.notmuch_message_get_tags
212 _get_tags.restype = c_void_p
214 def __init__(self, msg_p, parent=None):
216 msg_p is a pointer to an notmuch_message_t Structure. If it is None,
217 we will raise an NotmuchError(STATUS.NULL_POINTER).
219 Is a 'parent' object is passed which this message is derived from,
220 we save a reference to it, so we can automatically delete the parent
221 object once all derived objects are dead.
224 NotmuchError(STATUS.NULL_POINTER)
226 self._parent = parent
227 print "Inited Message derived from %s" %(str(parent))
230 def get_message_id(self):
231 """ return the msg id
233 Raises NotmuchError(STATUS.NOT_INITIALIZED) if not inited
235 if self._msg is None:
236 raise NotmuchError(STATUS.NOT_INITIALIZED)
237 return Message._get_message_id(self._msg)
240 def get_filename(self):
241 """ return the msg filename
243 Raises NotmuchError(STATUS.NOT_INITIALIZED) if not inited
245 if self._msg is None:
246 raise NotmuchError(STATUS.NOT_INITIALIZED)
247 return Message._get_filename(self._msg)
250 """ return the msg tags
252 Raises NotmuchError(STATUS.NOT_INITIALIZED) if not inited
253 Raises NotmuchError(STATUS.NULL_POINTER) on error.
255 if self._msg is None:
256 raise NotmuchError(STATUS.NOT_INITIALIZED)
258 tags_p = Message._get_tags(self._msg)
260 raise NotmuchError(STATUS.NULL_POINTER)
261 return Tags(tags_p, self)
264 """Close and free the notmuch Message"""
265 if self._msg is not None:
266 print("Freeing the Message now")
267 nmlib.notmuch_message_destroy (self._msg)