--- /dev/null
+import ctypes
+from ctypes import c_int, c_char_p, c_void_p
+from cnotmuch.globals import nmlib, STATUS, NotmuchError
+
+
+class Database(object):
+ """ Wrapper around a notmuch_database_t
+
+ Do note that as soon as we tear down this object, all derived queries,
+ threads, and messages will be freed as well.
+ """
+ #constants
+ MODE_READ_ONLY = 0
+ MODE_READ_WRITE = 1
+
+ _std_db_path = None
+ """Class attribute of users default database"""
+
+ """notmuch_database_get_path (notmuch_database_t *database)"""
+ _get_path = nmlib.notmuch_database_get_path
+ _get_path.restype = c_char_p
+
+ """notmuch_database_open (const char *path, notmuch_database_mode_t mode)"""
+ _open = nmlib.notmuch_database_open
+ _open.restype = c_void_p
+
+ """notmuch_database_get_all_tags (notmuch_database_t *database)"""
+ _get_all_tags = nmlib.notmuch_database_get_all_tags
+ _get_all_tags.restype = c_void_p
+
+ class notmuch_database_t(ctypes.Structure):
+ """the opaque database that is returned by functions."""
+ pass
+
+ def __init__(self, path=None, create=False, status= MODE_READ_ONLY):
+ """ Open or create a notmuch database"""
+ self._db = None
+ if create == False:
+ self.open(path, status)
+ else:
+ #TODO: implement
+ raise NotmuchError(message="Not implemented yet")
+
+ #TODO: make a proper function
+ create=nmlib.notmuch_database_create
+ """ notmuch_database_create(const char *path):"""
+
+ def open(self, path=None, status= MODE_READ_ONLY):
+ """calls notmuch_database_open
+
+ If path is None, we will try to read a users notmuch configuration and
+ use his default database.
+ :returns: Raises :exc:`notmuch.NotmuchError` in case
+ of any failure (after printing an error message on stderr).
+ """
+ if path is None:
+ if Database._std_db_path is None:
+ from ConfigParser import SafeConfigParser
+ import os.path
+ config = SafeConfigParser()
+ config.read(os.path.expanduser('~/.notmuch-config'))
+ if not config.has_option('database','path'):
+ raise NotmuchError(message=
+ "No DB path specified and no user default found")
+ Database._std_db_path=config.get('database','path')
+ path = Database._std_db_path
+
+ res = Database._open(path, status)
+
+ if res is None:
+ raise NotmuchError(
+ message="Could not open the specified database")
+ self._db = res
+
+ def get_path(self):
+ """notmuch_database_get_path (notmuch_database_t *database); """
+ return Database._get_path(self._db)
+
+ #TODO:implement
+ #If no message is found with the given message_id or if an
+ #out-of-memory situation occurs, this function returns NULL.
+ #notmuch_message_t *
+ #notmuch_database_find_message (notmuch_database_t *database,
+ # const char *message_id);
+
+ def get_all_tags(self):
+ """Return a Tags() object (list of all tags found in the database)
+
+ :returns: Tags() object or raises :exc:`NotmuchError` with
+ STATUS.NULL_POINTER on error
+ """
+ tags_p = Database._get_all_tags (self._db)
+ if tags_p == None:
+ raise NotmuchError(STATUS.NULL_POINTER)
+ return Tags(tags_p, self)
+
+ def __repr__(self):
+ return "'Notmuch DB " + self.get_path() + "'"
+
+ def __del__(self):
+ """Close and free the notmuch database if needed"""
+ if self._db is not None:
+ print("Freeing the database now")
+ nmlib.notmuch_database_close(self._db)
+
+ @property
+ def db_p(self):
+ """Returns a pointer to the current notmuch_database_t or None"""
+ return self._db
+
+
+#------------------------------------------------------------------------------
+class Tags(object):
+ """Wrapper around notmuch_tags_t"""
+ class notmuch_tags_t(ctypes.Structure):
+ """the opaque tags struct that is returned by functions."""
+ pass
+
+ #notmuch_tags_get
+ _get = nmlib.notmuch_tags_get
+ _get.restype = c_char_p
+
+ def __init__(self, tags_p, db=None):
+ """ Is passed the db these tags are derived from, and saves a
+ reference to it, so we can automatically delete the db object
+ once all derived objects are dead."""
+ self._tags = tags_p
+ self._db = db
+ print "inited tags with %d %s" %(tags_p, str(db))
+
+ def __iter__(self):
+ """ Make Tags an iterator """
+ return self
+
+ def next(self):
+ if self._tags is None:
+ raise StopIteration
+ nmlib.notmuch_tags_move_to_next(self._tags)
+ if not nmlib.notmuch_tags_valid(self._tags):
+ raise StopIteration
+ return Tags._get (self._tags)
+
+ def __del__(self):
+ """Close and free the notmuch tags"""
+ if self._tags is not None:
+ print("Freeing the Tags now")
+ nmlib.notmuch_tags_destroy (self._tags)
--- /dev/null
+from ctypes import CDLL, c_char_p, c_int
+#package-global instance of the notmuch library
+#TODO: lazy load this on first access?
+nmlib = CDLL('/usr/local/lib/libnotmuch.so')
+
+class STATUS(object):
+ SUCCESS = 0
+ OUT_OF_MEMORY = 1
+ READ_ONLY_DATABASE = 2
+ XAPIAN_EXCEPTION = 3
+ FILE_ERROR = 4
+ FILE_NOT_EMAIL = 5
+ DUPLICATE_MESSAGE_ID = 6
+ NULL_POINTER = 7
+ TAG_TOO_LONG = 8
+ UNBALANCED_FREEZE_THAW = 9
+ LAST_STATUS = 10
+
+ """Get a string representation of a notmuch_status_t value."""
+ status2str = nmlib.notmuch_status_to_string
+ status2str.restype = c_char_p
+ status2str.argtypes = [c_int]
+
+ def __init__(self, status):
+ self._status = status
+
+ def __str__(self):
+ """Get a string representation of a notmuch_status_t value."""
+ return str(STATUS.status2str(self._status))
+
+class NotmuchError(Exception):
+ def __init__(self, status=None, message=None):
+ """Is initiated with a (notmuch.STATUS[,message=None])"""
+ super(NotmuchError, self).__init__(message, status)
+
+ def __str__(self):
+ if self.args[0] is not None: return self.args[0]
+ else: return str(STATUS(self.args[1]))