--- swig/Makefile | 18 ++++ swig/notmuch.py | 222 ++++++++++++++++++++++++++++++++++++++++++++++++++ swig/notmuch_funcs.i | 9 ++ 3 files changed, 249 insertions(+), 0 deletions(-) create mode 100644 swig/Makefile create mode 100644 swig/notmuch.py create mode 100644 swig/notmuch_funcs.i diff --git a/swig/Makefile b/swig/Makefile new file mode 100644 index 0000000..7b10ea7 --- /dev/null +++ b/swig/Makefile @@ -0,0 +1,18 @@ +include ../Makefile.config + +INCLUDES=-I../lib -I/usr/include/python2.6 +CFLAGS=${INCLUDES} + +all : python + +python : _notmuch_funcs.so notmuch.py + +_notmuch_funcs.so : notmuch_funcs_wrap.o + g++ -shared -lnotmuch ${XAPIAN_LDFLAGS} ${GMIME_LDFLAGS} ${TALLOC_LDFLAGS} -o $@ $< + +%_wrap.o : %_wrap.c + gcc ${CFLAGS} -fPIC -c -o $@ $< + +%_wrap.c %.py : %.i + swig -python ${INCLUDES} $< + diff --git a/swig/notmuch.py b/swig/notmuch.py new file mode 100644 index 0000000..e17f71f --- /dev/null +++ b/swig/notmuch.py @@ -0,0 +1,222 @@ +import notmuch_funcs as nm +from datetime import datetime + +class Exception(Exception): + def get_message(): + errors = { + nm.NOTMUCH_STATUS_OUT_OF_MEMORY: 'out of memory', + nm.NOTMUCH_STATUS_READONLY_DATABASE: 'database opened as read-only', + nm.NOTMUCH_STATUS_XAPIAN_EXCEPTION: 'xapian error', + nm.NOTMUCH_STATUS_FILE_ERROR: 'file error', + nm.NOTMUCH_STATUS_FILE_NOT_EMAIL: 'file not email message', + nm.NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: 'duplicate message id', + nm.NOTMUCH_STATUS_NULL_POINTER: 'null pointer', + nm.NOTMUCH_STATUS_TAG_TOO_LONG: 'tag name too long', + nm.NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: 'unbalanced freeze/thaw', + } + return errors.get(self.status, 'unknown error') + + def __init__(self, status): + self.status = status + +def _handle_status(status): + if (status != nm.NOTMUCH_STATUS_SUCCESS): + raise Exception(status) + +class Database(object): + MODE_READ_ONLY = nm.NOTMUCH_DATABASE_MODE_READ_ONLY + MODE_READ_WRITE = nm.NOTMUCH_DATABASE_MODE_READ_WRITE + + def __init__(self, db): + if not db: + raise Exception("Failed to open database") + self.db = db + + @staticmethod + def create(path): + return Database(nm.notmuch_database_create(path)) + + @staticmethod + def open(path, mode): + return Database(nm.notmuch_database_open(path, mode)) + + def close(self): + nm.notmuch_database_close(self.db) + + def get_path(self): + return nm.notmuch_database_get_path(self.db) + + def set_timestamp(self, key, timestamp): + _handle_status(nm.notmuch_database_set_timestamp(self.db, key, timestamp)) + + def get_timestamp(self, key): + return datetime.fromtimestamp(nm.notmuch_database_get_timestamp(self.db, key)) + + def add_message(self, filename, message): + _handle_status(nm.notmuch_database_add_message(self.db, filename, message.message)) + + def find_message(self, message_id): + return Message(nm.notmuch_database_find_message(self.db, message_id)) + + def get_all_tags(self): + return Tags(nm.notmuch_database_get_all_tags(self.db)) + + def __destroy__(self): + self.close() + +class Query(object): + def __init__(self, db, query_string): + self.query = nm.notmuch_query_create(db, query_string) + if not self.query: # This might not work + raise "Failed to create query" + + def set_sort(self, sort): + nm.notmuch_query_set_sort(self.query, sort) + + def search_threads(self): + return Threads(nm.notmuch_query_search_threads(self.query)) + + def search_messages(self): + return Messages(nm.notmuch_query_search_messages(self.query)) + + def count_message(self): + return nm.notmuch_query_count_messages(self.query) + + def __destroy__(self): + nm.notmuch_query_destroy(self.query) + +class Tags(object): + def __init__(self, tags): + self.tags = tags + + def __iter__(self): + return self + + def next(self): + if not nm.notmuch_tags_has_more(self.tags): + raise StopIteration + else: + h = nm.notmuch_tags_get(self.tags) + nm.notmuch_tags_advance(self.tags) + return h + + def __destroy__(self): + nm.notmuch_messages_destroy(self.tags) + +class Thread(object): + def __init__(self, thread): + self.thread = thread + + def get_thread_id(self): + return nm.notmuch_thread_get_thread_id(self.thread) + + def get_total_messages(self): + return nm.notmuch_thread_total_messages(self.thread) + + def get_toplevel_messages(self): + return Messages(nm.notmuch_thread_get_toplevel_messages(self.thread)) + + def get_matched_messages(self): + return nm.notmuch_thread_get_matched_messages(self.thread) + + def get_authors(self): + return nm.notmuch_thread_get_authors(self.thread) + + def get_subject(self): + return nm.notmuch_thread_get_subject(self.thread) + + def get_oldest_date(self): + return nm.notmuch_thread_get_oldest_date(self.thread) + + def get_newest_date(self): + return nm.notmuch_thread_get_newest_date(self.thread) + + def get_tags(self): + return Tags(nm.notmuch_thread_get_tags(self.thread)) + + def __destroy__(self): + nm.notmuch_thread_destroy(self.thread) + +class Threads(object): + def __init__(self, threads): + self.threads = threads + + def __iter__(self): + return self + + def next(self): + if not nm.notmuch_threads_has_more(self.threads): + raise StopIteration + else: + h = Thread(nm.notmuch_threads_get(self.threads)) + nm.notmuch_threads_advance(self.threads) + return h + + def __destroy__(self): + nm.notmuch_threads_destroy(self.threads) + +class Messages(object): + def __init__(self, messages): + self.messages = messages + + def __iter__(self): + return self + + def next(self): + if not nm.notmuch_messages_has_more(self.messages): + raise StopIteration + else: + h = Message(nm.notmuch_messages_get(self.messages)) + nm.notmuch_messages_advance(self.messages) + return h + + def __destroy__(self): + nm.notmuch_messages_destroy(self.messages) + + def collect_tags(self): + return Tags(nm.notmuch_messages_collect_tags(self.messages)) + +class Message(object): + def __init__(self, message): + self.message = message + + def get_replies(self): + return Messages(nm.notmuch_message_get_replies(self.message)) + + def get_filename(self): + return nm.notmuch_message_get_filename(self.message) + + def get_flag(self, flag): + return bool(nm.notmuch_message_get_flag(self.message, flag)) + + def set_flag(self, flag, value): + return nm.notmuch_message_set_flag(self.message, flag, value) + + def get_date(self): + return datetime.fromtimestamp(nm.notmuch_message_get_date(self.message)) + + def get_header(self, header): + return nm.notmuch_message_get_header(self.message, header) + + def get_tags(self): + return Tags(nm.notmuch_message_get_tags(self.message)) + + def add_tag(self, tag): + _handle_status(nm.notmuch_message_add_tag(self.message, tag)) + + def remove_tag(self, tag): + _handle_status(nm.notmuch_message_remove_tag(self.message, tag)) + + def remove_all_tags(self): + nm.notmuch_message_remove_all_tags(self.message) + + def freeze(self): + nm.notmuch_message_freeze(self.message) + + def thaw(self): + nm.notmuch_message_thaw(self.message) + + def __destroy__(self): + nm.notmuch_message_destroy(self.message) + + diff --git a/swig/notmuch_funcs.i b/swig/notmuch_funcs.i new file mode 100644 index 0000000..cc1826e --- /dev/null +++ b/swig/notmuch_funcs.i @@ -0,0 +1,9 @@ +%module notmuch_funcs + +%{ +#define SWIG_FILE_WITH_INIT +#include "notmuch.h" +%} + +%include "notmuch.h" + -- 1.6.3.3