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"""
145 #------------------------------------------------------------------------------
147 """ Wrapper around a notmuch_query_t
149 Do note that as soon as we tear down this object, all derived
150 threads, and messages will be freed as well.
153 SORT_OLDEST_FIRST = 0
154 SORT_NEWEST_FIRST = 1
157 """notmuch_query_create"""
158 _create = nmlib.notmuch_query_create
159 _create.restype = c_void_p
161 """notmuch_query_search_messages"""
162 _search_messages = nmlib.notmuch_query_search_messages
163 _search_messages.restype = c_void_p
165 def __init__(self, db, querystr):
169 self.create(db, querystr)
171 def create(self, db, querystr):
172 """db is a Database() and querystr a string
174 raises NotmuchError STATUS.NOT_INITIALIZED if db is not inited and
175 STATUS.NULL_POINTER if the query creation failed (too little memory)
178 raise NotmuchError(STATUS.NOT_INITIALIZED)
179 # create reference to parent db to keep it alive
182 # create query, return None if too little mem available
183 query_p = Query._create(db.db_p, querystr)
185 NotmuchError(STATUS.NULL_POINTER)
186 self._query = query_p
189 def search_messages(self):
190 """notmuch_query_search_messages
191 Returns Messages() or a raises a NotmuchError()
193 if self._query is None:
194 raise NotmuchError(STATUS.NOT_INITIALIZED)
196 msgs_p = Query._search_messages(self._query)
199 NotmuchError(STATUS.NULL_POINTER)
201 return Messages(msgs_p,self)
205 """Close and free the Query"""
206 if self._query is not None:
207 print("Freeing the Query now")
208 nmlib.notmuch_query_destroy (self._query)
210 #------------------------------------------------------------------------------
212 """Wrapper around notmuch_tags_t"""
215 _get = nmlib.notmuch_tags_get
216 _get.restype = c_char_p
218 def __init__(self, tags_p, db=None):
220 msg_p is a pointer to an notmuch_message_t Structure. If it is None,
221 we will raise an NotmuchError(STATUS.NULL_POINTER).
223 Is passed the db these tags are derived from, and saves a
224 reference to it, so we can automatically delete the db object
225 once all derived objects are dead.
227 Tags() provides an iterator over all contained tags. However, you will
228 only be able to iterate over the Tags once, because the underlying C
229 function only allows iterating once.
230 #TODO: make the iterator work more than once and cache the tags in
234 NotmuchError(STATUS.NULL_POINTER)
238 print "Inited Tags derived from %s" %(str(db))
241 """ Make Tags an iterator """
242 if self._tags is None:
243 raise NotmuchError(STATUS.NOT_INITIALIZED)
247 nmlib.notmuch_tags_move_to_next(self._tags)
248 if not nmlib.notmuch_tags_valid(self._tags):
249 print("Freeing the Tags now")
250 nmlib.notmuch_tags_destroy (self._tags)
252 return Tags._get (self._tags)
255 """Close and free the notmuch tags"""
256 if self._tags is not None:
257 print("Freeing the Tags now")
258 nmlib.notmuch_tags_destroy (self._tags)
261 #------------------------------------------------------------------------------
262 class Messages(object):
263 """Wrapper around notmuch_messages_t"""
266 _get = nmlib.notmuch_messages_get
267 _get.restype = c_void_p
269 def __init__(self, msgs_p, parent=None):
271 msg_p is a pointer to an notmuch_messages_t Structure. If it is None,
272 we will raise an NotmuchError(STATUS.NULL_POINTER).
274 If passed the parent query this Messages() is derived from, it saves a
275 reference to it, so we can automatically delete the parent query object
276 once all derived objects are dead.
278 Messages() provides an iterator over all contained Message()s.
279 However, you will only be able to iterate over it once,
280 because the underlying C function only allows iterating once.
281 #TODO: make the iterator work more than once and cache the tags in
285 NotmuchError(STATUS.NULL_POINTER)
288 #store parent, so we keep them alive as long as self is alive
289 self._parent = parent
290 print "Inited Messages derived from %s" %(str(parent))
293 """ Make Messages an iterator """
297 if self._msgs is None:
298 raise NotmuchError(STATUS.NOT_INITIALIZED)
300 nmlib.notmuch_messages_move_to_next(self._msgs)
301 if not nmlib.notmuch_messages_valid(self._msgs):
302 print("Freeing the Messages now")
303 nmlib.notmuch_messages_destroy (self._msgs)
306 return Message(Messages._get (self._msgs), self)
309 """Close and free the notmuch Messages"""
310 if self._msgs is not None:
311 print("Freeing the Messages now")
312 nmlib.notmuch_messages_destroy (self._msgs)
315 #------------------------------------------------------------------------------
316 class Message(object):
317 """Wrapper around notmuch_message_t"""
319 """notmuch_message_get_filename (notmuch_message_t *message)"""
320 _get_filename = nmlib.notmuch_message_get_filename
321 _get_filename.restype = c_char_p
322 """notmuch_message_get_message_id (notmuch_message_t *message)"""
323 _get_message_id = nmlib.notmuch_message_get_message_id
324 _get_message_id.restype = c_char_p
326 """notmuch_message_get_tags (notmuch_message_t *message)"""
327 _get_tags = nmlib.notmuch_message_get_tags
328 _get_tags.restype = c_void_p
330 def __init__(self, msg_p, parent=None):
332 msg_p is a pointer to an notmuch_message_t Structure. If it is None,
333 we will raise an NotmuchError(STATUS.NULL_POINTER).
335 Is a 'parent' object is passed which this message is derived from,
336 we save a reference to it, so we can automatically delete the parent
337 object once all derived objects are dead.
340 NotmuchError(STATUS.NULL_POINTER)
342 self._parent = parent
343 print "Inited Message derived from %s" %(str(parent))
346 def get_message_id(self):
347 """ return the msg id
349 Raises NotmuchError(STATUS.NOT_INITIALIZED) if not inited
351 if self._msg is None:
352 raise NotmuchError(STATUS.NOT_INITIALIZED)
353 return Message._get_message_id(self._msg)
356 def get_filename(self):
357 """ return the msg filename
359 Raises NotmuchError(STATUS.NOT_INITIALIZED) if not inited
361 if self._msg is None:
362 raise NotmuchError(STATUS.NOT_INITIALIZED)
363 return Message._get_filename(self._msg)
366 """ return the msg tags
368 Raises NotmuchError(STATUS.NOT_INITIALIZED) if not inited
369 Raises NotmuchError(STATUS.NULL_POINTER) on error.
371 if self._msg is None:
372 raise NotmuchError(STATUS.NOT_INITIALIZED)
374 tags_p = Message._get_tags(self._msg)
376 raise NotmuchError(STATUS.NULL_POINTER)
377 return Tags(tags_p, self)
380 """Close and free the notmuch Message"""
381 if self._msg is not None:
382 print("Freeing the Message now")
383 nmlib.notmuch_message_destroy (self._msg)