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.
152 def __init__(self, db, querystr):
155 #------------------------------------------------------------------------------
157 """Wrapper around notmuch_tags_t"""
158 class notmuch_tags_t(ctypes.Structure):
159 """the opaque tags struct that is returned by functions."""
163 _get = nmlib.notmuch_tags_get
164 _get.restype = c_char_p
166 def __init__(self, tags_p, db=None):
168 msg_p is a pointer to an notmuch_message_t Structure. If it is None,
169 we will raise an NotmuchError(STATUS.NULL_POINTER).
171 Is passed the db these tags are derived from, and saves a
172 reference to it, so we can automatically delete the db object
173 once all derived objects are dead.
175 Tags() provides an iterator over all contained tags. However, you will
176 only be able to iterate over the Tags once, because the underlying C
177 function only allows iterating once.
178 #TODO: make the iterator work more than once and cache the tags in
182 NotmuchError(STATUS.NULL_POINTER)
186 print "Inited Tags derived from %s" %(str(db))
189 """ Make Tags an iterator """
193 if self._tags is None:
195 nmlib.notmuch_tags_move_to_next(self._tags)
196 if not nmlib.notmuch_tags_valid(self._tags):
197 print("Freeing the Tags now")
198 nmlib.notmuch_tags_destroy (self._tags)
200 return Tags._get (self._tags)
203 """Close and free the notmuch tags"""
204 if self._tags is not None:
205 print("Freeing the Tags now")
206 nmlib.notmuch_tags_destroy (self._tags)
208 #------------------------------------------------------------------------------
209 class Message(object):
210 """Wrapper around notmuch_message_t"""
212 """notmuch_message_get_filename (notmuch_message_t *message)"""
213 _get_filename = nmlib.notmuch_message_get_filename
214 _get_filename.restype = c_char_p
215 """notmuch_message_get_message_id (notmuch_message_t *message)"""
216 _get_message_id = nmlib.notmuch_message_get_message_id
217 _get_message_id.restype = c_char_p
219 """notmuch_message_get_tags (notmuch_message_t *message)"""
220 _get_tags = nmlib.notmuch_message_get_tags
221 _get_tags.restype = c_void_p
223 def __init__(self, msg_p, parent=None):
225 msg_p is a pointer to an notmuch_message_t Structure. If it is None,
226 we will raise an NotmuchError(STATUS.NULL_POINTER).
228 Is a 'parent' object is passed which this message is derived from,
229 we save a reference to it, so we can automatically delete the parent
230 object once all derived objects are dead.
233 NotmuchError(STATUS.NULL_POINTER)
235 self._parent = parent
236 print "Inited Message derived from %s" %(str(parent))
239 def get_message_id(self):
240 """ return the msg id
242 Raises NotmuchError(STATUS.NOT_INITIALIZED) if not inited
244 if self._msg is None:
245 raise NotmuchError(STATUS.NOT_INITIALIZED)
246 return Message._get_message_id(self._msg)
249 def get_filename(self):
250 """ return the msg filename
252 Raises NotmuchError(STATUS.NOT_INITIALIZED) if not inited
254 if self._msg is None:
255 raise NotmuchError(STATUS.NOT_INITIALIZED)
256 return Message._get_filename(self._msg)
259 """ return the msg tags
261 Raises NotmuchError(STATUS.NOT_INITIALIZED) if not inited
262 Raises NotmuchError(STATUS.NULL_POINTER) on error.
264 if self._msg is None:
265 raise NotmuchError(STATUS.NOT_INITIALIZED)
267 tags_p = Message._get_tags(self._msg)
269 raise NotmuchError(STATUS.NULL_POINTER)
270 return Tags(tags_p, self)
273 """Close and free the notmuch Message"""
274 if self._msg is not None:
275 print("Freeing the Message now")
276 nmlib.notmuch_message_destroy (self._msg)