--- /dev/null
+Return-Path: <teythoon@jade-hamburg.de>\r
+X-Original-To: notmuch@notmuchmail.org\r
+Delivered-To: notmuch@notmuchmail.org\r
+Received: from localhost (localhost [127.0.0.1])\r
+ by olra.theworths.org (Postfix) with ESMTP id C0C7E429E25\r
+ for <notmuch@notmuchmail.org>; Sun, 9 Oct 2011 15:13:45 -0700 (PDT)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: 0.001\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=0.001 tagged_above=-999 required=5\r
+ tests=[UNPARSEABLE_RELAY=0.001] autolearn=disabled\r
+Received: from olra.theworths.org ([127.0.0.1])\r
+ by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
+ with ESMTP id KcPOLsTVLwUh for <notmuch@notmuchmail.org>;\r
+ Sun, 9 Oct 2011 15:13:43 -0700 (PDT)\r
+Received: from mail.cryptobitch.de (cryptobitch.de [88.198.7.68])\r
+ (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits))\r
+ (No client certificate requested)\r
+ by olra.theworths.org (Postfix) with ESMTPS id 344A8431FB6\r
+ for <notmuch@notmuchmail.org>; Sun, 9 Oct 2011 15:13:43 -0700 (PDT)\r
+Received: from mail.jade-hamburg.de (unknown [85.183.11.228])\r
+ (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits))\r
+ (No client certificate requested)\r
+ by mail.cryptobitch.de (Postfix) with ESMTPSA id E1747509367\r
+ for <notmuch@notmuchmail.org>; Mon, 10 Oct 2011 00:13:41 +0200 (CEST)\r
+Received: by mail.jade-hamburg.de (Postfix, from userid 401)\r
+ id 60011DF2A1; Mon, 10 Oct 2011 00:13:41 +0200 (CEST)\r
+Received: from thinkbox.jade-hamburg.de (unknown\r
+ [IPv6:fe80::216:d3ff:fe3e:5058%br0])\r
+ (using TLSv1 with cipher AES256-SHA (256/256 bits))\r
+ (No client certificate requested) (Authenticated sender: teythoon)\r
+ by mail.jade-hamburg.de (Postfix) with ESMTPSA id 680C2DF29F;\r
+ Mon, 10 Oct 2011 00:13:22 +0200 (CEST)\r
+Received: from teythoon by thinkbox.jade-hamburg.de with local (Exim 4.76)\r
+ (envelope-from <teythoon@thinkbox.jade-hamburg.de>)\r
+ id 1RD1cX-0000HM-JH; Mon, 10 Oct 2011 00:13:21 +0200\r
+From: Justus Winter <4winter@informatik.uni-hamburg.de>\r
+To: notmuch@notmuchmail.org\r
+Subject: [PATCH 2/2] python: annotate all calls into libnotmuch with types\r
+Date: Mon, 10 Oct 2011 00:12:54 +0200\r
+Message-Id:\r
+ <1318198374-926-2-git-send-email-4winter@informatik.uni-hamburg.de>\r
+X-Mailer: git-send-email 1.7.6.3\r
+In-Reply-To:\r
+ <1318198374-926-1-git-send-email-4winter@informatik.uni-hamburg.de>\r
+References:\r
+ <1318198374-926-1-git-send-email-4winter@informatik.uni-hamburg.de>\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.13\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+ <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
+List-Post: <mailto:notmuch@notmuchmail.org>\r
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Sun, 09 Oct 2011 22:13:45 -0000\r
+\r
+Add type information to the ctypes._FuncPtr wrappers and\r
+use the wrapper classes instead of c_void_p for pointers\r
+to notmuch_*_t.\r
+\r
+This enables the ctypes library to type check parameters\r
+being handed to functions from the notmuch library.\r
+\r
+Signed-off-by: Justus Winter <4winter@informatik.uni-hamburg.de>\r
+---\r
+ bindings/python/notmuch/database.py | 127 ++++++++++++++++++++++++++--------\r
+ bindings/python/notmuch/filename.py | 22 +++++-\r
+ bindings/python/notmuch/message.py | 91 ++++++++++++++++++++-----\r
+ bindings/python/notmuch/tag.py | 23 +++++--\r
+ bindings/python/notmuch/thread.py | 63 +++++++++++++----\r
+ 5 files changed, 255 insertions(+), 71 deletions(-)\r
+\r
+diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py\r
+index f4bc53e..25b4b1b 100644\r
+--- a/bindings/python/notmuch/database.py\r
++++ b/bindings/python/notmuch/database.py\r
+@@ -18,9 +18,11 @@ Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'\r
+ """\r
+ \r
+ import os\r
+-from ctypes import c_int, c_char_p, c_void_p, c_uint, c_long, byref\r
++from ctypes import c_int, c_char_p, c_void_p, c_uint, c_long, byref, POINTER\r
+ from notmuch.globals import (nmlib, STATUS, NotmuchError, NotInitializedError,\r
+- NullPointerError, OutOfMemoryError, XapianError, Enum, _str)\r
++ NullPointerError, OutOfMemoryError, XapianError, Enum, _str,\r
++ NotmuchDatabaseP, NotmuchDirectoryP, NotmuchMessageP, NotmuchTagsP,\r
++ NotmuchQueryP, NotmuchMessagesP, NotmuchThreadsP, NotmuchFilenamesP)\r
+ from notmuch.thread import Threads\r
+ from notmuch.message import Messages, Message\r
+ from notmuch.tag import Tags\r
+@@ -56,37 +58,48 @@ class Database(object):\r
+ \r
+ """notmuch_database_get_directory"""\r
+ _get_directory = nmlib.notmuch_database_get_directory\r
+- _get_directory.restype = c_void_p\r
++ _get_directory.argtypes = [NotmuchDatabaseP, c_char_p]\r
++ _get_directory.restype = NotmuchDirectoryP\r
+ \r
+ """notmuch_database_get_path"""\r
+ _get_path = nmlib.notmuch_database_get_path\r
++ _get_path.argtypes = [NotmuchDatabaseP]\r
+ _get_path.restype = c_char_p\r
+ \r
+ """notmuch_database_get_version"""\r
+ _get_version = nmlib.notmuch_database_get_version\r
++ _get_version.argtypes = [NotmuchDatabaseP]\r
+ _get_version.restype = c_uint\r
+ \r
+ """notmuch_database_open"""\r
+ _open = nmlib.notmuch_database_open\r
+- _open.restype = c_void_p\r
++ _open.argtypes = [c_char_p, c_uint]\r
++ _open.restype = NotmuchDatabaseP\r
+ \r
+ """notmuch_database_upgrade"""\r
+ _upgrade = nmlib.notmuch_database_upgrade\r
+- _upgrade.argtypes = [c_void_p, c_void_p, c_void_p]\r
++ _upgrade.argtypes = [NotmuchDatabaseP, c_void_p, c_void_p]\r
++ _upgrade.restype = c_uint\r
+ \r
+ """ notmuch_database_find_message"""\r
+ _find_message = nmlib.notmuch_database_find_message\r
++ _find_message.argtypes = [NotmuchDatabaseP, c_char_p, POINTER(NotmuchMessageP)]\r
++ _find_message.restype = c_uint\r
+ \r
+ """notmuch_database_find_message_by_filename"""\r
+ _find_message_by_filename = nmlib.notmuch_database_find_message_by_filename\r
++ _find_message_by_filename.argtypes = [NotmuchDatabaseP, c_char_p, POINTER(NotmuchMessageP)]\r
++ _find_message_by_filename.restype = c_uint\r
+ \r
+ """notmuch_database_get_all_tags"""\r
+ _get_all_tags = nmlib.notmuch_database_get_all_tags\r
+- _get_all_tags.restype = c_void_p\r
++ _get_all_tags.argtypes = [NotmuchDatabaseP]\r
++ _get_all_tags.restype = NotmuchTagsP\r
+ \r
+ """notmuch_database_create"""\r
+ _create = nmlib.notmuch_database_create\r
+- _create.restype = c_void_p\r
++ _create.argtypes = [c_char_p]\r
++ _create.restype = NotmuchDatabaseP\r
+ \r
+ def __init__(self, path=None, create=False, mode=0):\r
+ """If *path* is `None`, we will try to read a users notmuch\r
+@@ -186,6 +199,10 @@ class Database(object):\r
+ self._assert_db_is_initialized()\r
+ return Database._get_version(self._db)\r
+ \r
++ _needs_upgrade = nmlib.notmuch_database_needs_upgrade\r
++ _needs_upgrade.argtypes = [NotmuchDatabaseP]\r
++ _needs_upgrade.restype = bool\r
++\r
+ def needs_upgrade(self):\r
+ """Does this database need to be upgraded before writing to it?\r
+ \r
+@@ -197,7 +214,7 @@ class Database(object):\r
+ :returns: `True` or `False`\r
+ """\r
+ self._assert_db_is_initialized()\r
+- return nmlib.notmuch_database_needs_upgrade(self._db)\r
++ return self._needs_upgrade(self._db)\r
+ \r
+ def upgrade(self):\r
+ """Upgrades the current database\r
+@@ -219,6 +236,10 @@ class Database(object):\r
+ #TODO: catch exceptions, document return values and etc\r
+ return status\r
+ \r
++ _begin_atomic = nmlib.notmuch_database_begin_atomic\r
++ _begin_atomic.argtypes = [NotmuchDatabaseP]\r
++ _begin_atomic.restype = c_uint\r
++\r
+ def begin_atomic(self):\r
+ """Begin an atomic database operation\r
+ \r
+@@ -236,11 +257,15 @@ class Database(object):\r
+ \r
+ *Added in notmuch 0.9*"""\r
+ self._assert_db_is_initialized()\r
+- status = nmlib.notmuch_database_begin_atomic(self._db)\r
++ status = self._begin_atomic(self._db)\r
+ if status != STATUS.SUCCESS:\r
+ raise NotmuchError(status)\r
+ return status\r
+ \r
++ _end_atomic = nmlib.notmuch_database_end_atomic\r
++ _end_atomic.argtypes = [NotmuchDatabaseP]\r
++ _end_atomic.restype = c_uint\r
++\r
+ def end_atomic(self):\r
+ """Indicate the end of an atomic database operation\r
+ \r
+@@ -258,7 +283,7 @@ class Database(object):\r
+ \r
+ *Added in notmuch 0.9*"""\r
+ self._assert_db_is_initialized()\r
+- status = nmlib.notmuch_database_end_atomic(self._db)\r
++ status = self._end_atomic(self._db)\r
+ if status != STATUS.SUCCESS:\r
+ raise NotmuchError(status)\r
+ return status\r
+@@ -299,6 +324,10 @@ class Database(object):\r
+ # return the Directory, init it with the absolute path\r
+ return Directory(_str(abs_dirpath), dir_p, self)\r
+ \r
++ _add_message = nmlib.notmuch_database_add_message\r
++ _add_message.argtypes = [NotmuchDatabaseP, c_char_p, POINTER(NotmuchMessageP)]\r
++ _add_message.restype = c_uint\r
++\r
+ def add_message(self, filename, sync_maildir_flags=False):\r
+ """Adds a new message to the database\r
+ \r
+@@ -350,9 +379,7 @@ class Database(object):\r
+ """\r
+ self._assert_db_is_initialized()\r
+ msg_p = c_void_p()\r
+- status = nmlib.notmuch_database_add_message(self._db,\r
+- _str(filename),\r
+- byref(msg_p))\r
++ status = self._add_message(self._db, _str(filename), byref(msg_p))\r
+ \r
+ if not status in [STATUS.SUCCESS, STATUS.DUPLICATE_MESSAGE_ID]:\r
+ raise NotmuchError(status)\r
+@@ -364,6 +391,10 @@ class Database(object):\r
+ msg.maildir_flags_to_tags()\r
+ return (msg, status)\r
+ \r
++ _remove_message = nmlib.notmuch_database_remove_message\r
++ _remove_message.argtypes = [NotmuchDatabaseP, c_char_p]\r
++ _remove_message.restype = c_uint\r
++\r
+ def remove_message(self, filename):\r
+ """Removes a message (filename) from the given notmuch database\r
+ \r
+@@ -392,8 +423,7 @@ class Database(object):\r
+ removed.\r
+ """\r
+ self._assert_db_is_initialized()\r
+- return nmlib.notmuch_database_remove_message(self._db,\r
+- filename)\r
++ return self._remove_message(self._db, filename)\r
+ \r
+ def find_message(self, msgid):\r
+ """Returns a :class:`Message` as identified by its message ID\r
+@@ -491,10 +521,14 @@ class Database(object):\r
+ def __repr__(self):\r
+ return "'Notmuch DB " + self.get_path() + "'"\r
+ \r
++ _close = nmlib.notmuch_database_close\r
++ _close.argtypes = [NotmuchDatabaseP]\r
++ _close.restype = None\r
++\r
+ def __del__(self):\r
+ """Close and free the notmuch database if needed"""\r
+ if self._db is not None:\r
+- nmlib.notmuch_database_close(self._db)\r
++ self._close(self._db)\r
+ \r
+ def _get_user_default_db(self):\r
+ """ Reads a user's notmuch config and returns his db location\r
+@@ -545,18 +579,22 @@ class Query(object):\r
+ \r
+ """notmuch_query_create"""\r
+ _create = nmlib.notmuch_query_create\r
+- _create.restype = c_void_p\r
++ _create.argtypes = [NotmuchDatabaseP, c_char_p]\r
++ _create.restype = NotmuchQueryP\r
+ \r
+ """notmuch_query_search_threads"""\r
+ _search_threads = nmlib.notmuch_query_search_threads\r
+- _search_threads.restype = c_void_p\r
++ _search_threads.argtypes = [NotmuchQueryP]\r
++ _search_threads.restype = NotmuchThreadsP\r
+ \r
+ """notmuch_query_search_messages"""\r
+ _search_messages = nmlib.notmuch_query_search_messages\r
+- _search_messages.restype = c_void_p\r
++ _search_messages.argtypes = [NotmuchQueryP]\r
++ _search_messages.restype = NotmuchMessagesP\r
+ \r
+ """notmuch_query_count_messages"""\r
+ _count_messages = nmlib.notmuch_query_count_messages\r
++ _count_messages.argtypes = [NotmuchQueryP]\r
+ _count_messages.restype = c_uint\r
+ \r
+ def __init__(self, db, querystr):\r
+@@ -602,6 +640,10 @@ class Query(object):\r
+ raise NullPointerError\r
+ self._query = query_p\r
+ \r
++ _set_sort = nmlib.notmuch_query_set_sort\r
++ _set_sort.argtypes = [NotmuchQueryP, c_uint]\r
++ _set_sort.argtypes = None\r
++\r
+ def set_sort(self, sort):\r
+ """Set the sort order future results will be delivered in\r
+ \r
+@@ -609,7 +651,7 @@ class Query(object):\r
+ """\r
+ self._assert_query_is_initialized()\r
+ self.sort = sort\r
+- nmlib.notmuch_query_set_sort(self._query, sort)\r
++ self._set_sort(self._query, sort)\r
+ \r
+ def search_threads(self):\r
+ """Execute a query for threads\r
+@@ -661,10 +703,14 @@ class Query(object):\r
+ self._assert_query_is_initialized()\r
+ return Query._count_messages(self._query)\r
+ \r
++ _destroy = nmlib.notmuch_query_destroy\r
++ _destroy.argtypes = [NotmuchQueryP]\r
++ _destroy.restype = None\r
++\r
+ def __del__(self):\r
+ """Close and free the Query"""\r
+ if self._query is not None:\r
+- nmlib.notmuch_query_destroy(self._query)\r
++ self._destroy(self._query)\r
+ \r
+ \r
+ class Directory(object):\r
+@@ -683,19 +729,23 @@ class Directory(object):\r
+ \r
+ """notmuch_directory_get_mtime"""\r
+ _get_mtime = nmlib.notmuch_directory_get_mtime\r
++ _get_mtime.argtypes = [NotmuchDirectoryP]\r
+ _get_mtime.restype = c_long\r
+ \r
+ """notmuch_directory_set_mtime"""\r
+ _set_mtime = nmlib.notmuch_directory_set_mtime\r
+- _set_mtime.argtypes = [c_char_p, c_long]\r
++ _set_mtime.argtypes = [NotmuchDirectoryP, c_long]\r
++ _set_mtime.restype = c_uint\r
+ \r
+ """notmuch_directory_get_child_files"""\r
+ _get_child_files = nmlib.notmuch_directory_get_child_files\r
+- _get_child_files.restype = c_void_p\r
++ _get_child_files.argtypes = [NotmuchDirectoryP]\r
++ _get_child_files.restype = NotmuchFilenamesP\r
+ \r
+ """notmuch_directory_get_child_directories"""\r
+ _get_child_directories = nmlib.notmuch_directory_get_child_directories\r
+- _get_child_directories.restype = c_void_p\r
++ _get_child_directories.argtypes = [NotmuchDirectoryP]\r
++ _get_child_directories.restype = NotmuchFilenamesP\r
+ \r
+ def _assert_dir_is_initialized(self):\r
+ """Raises a NotmuchError(:attr:`STATUS`.NOT_INITIALIZED) if dir_p is None"""\r
+@@ -815,10 +865,14 @@ class Directory(object):\r
+ """Object representation"""\r
+ return "<notmuch Directory object '%s'>" % self._path\r
+ \r
++ _destroy = nmlib.notmuch_directory_destroy\r
++ _destroy.argtypes = [NotmuchDirectoryP]\r
++ _destroy.argtypes = None\r
++\r
+ def __del__(self):\r
+ """Close and free the Directory"""\r
+ if self._dir_p is not None:\r
+- nmlib.notmuch_directory_destroy(self._dir_p)\r
++ self._destroy(self._dir_p)\r
+ \r
+ \r
+ class Filenames(object):\r
+@@ -826,6 +880,7 @@ class Filenames(object):\r
+ \r
+ #notmuch_filenames_get\r
+ _get = nmlib.notmuch_filenames_get\r
++ _get.argtypes = [NotmuchFilenamesP]\r
+ _get.restype = c_char_p\r
+ \r
+ def __init__(self, files_p, parent):\r
+@@ -844,16 +899,24 @@ class Filenames(object):\r
+ """ Make Filenames an iterator """\r
+ return self\r
+ \r
++ _valid = nmlib.notmuch_filenames_valid\r
++ _valid.argtypes = [NotmuchFilenamesP]\r
++ _valid.restype = bool\r
++\r
++ _move_to_next = nmlib.notmuch_filenames_move_to_next\r
++ _move_to_next.argtypes = [NotmuchFilenamesP]\r
++ _move_to_next.restype = None\r
++\r
+ def next(self):\r
+ if self._files_p is None:\r
+ raise NotmuchError(STATUS.NOT_INITIALIZED)\r
+ \r
+- if not nmlib.notmuch_filenames_valid(self._files_p):\r
++ if not self._valid(self._files_p):\r
+ self._files_p = None\r
+ raise StopIteration\r
+ \r
+ file = Filenames._get(self._files_p)\r
+- nmlib.notmuch_filenames_move_to_next(self._files_p)\r
++ self._move_to_next(self._files_p)\r
+ return file\r
+ \r
+ def __len__(self):\r
+@@ -872,13 +935,17 @@ class Filenames(object):\r
+ raise NotmuchError(STATUS.NOT_INITIALIZED)\r
+ \r
+ i = 0\r
+- while nmlib.notmuch_filenames_valid(self._files_p):\r
+- nmlib.notmuch_filenames_move_to_next(self._files_p)\r
++ while self._valid(self._files_p):\r
++ self._move_to_next(self._files_p)\r
+ i += 1\r
+ self._files_p = None\r
+ return i\r
+ \r
++ _destroy = nmlib.notmuch_filenames_destroy\r
++ _destroy.argtypes = [NotmuchFilenamesP]\r
++ _destroy.restype = None\r
++\r
+ def __del__(self):\r
+ """Close and free Filenames"""\r
+ if self._files_p is not None:\r
+- nmlib.notmuch_filenames_destroy(self._files_p)\r
++ self._destroy(self._files_p)\r
+diff --git a/bindings/python/notmuch/filename.py b/bindings/python/notmuch/filename.py\r
+index de4d785..077754e 100644\r
+--- a/bindings/python/notmuch/filename.py\r
++++ b/bindings/python/notmuch/filename.py\r
+@@ -17,7 +17,8 @@ along with notmuch. If not, see <http://www.gnu.org/licenses/>.\r
+ Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'\r
+ """\r
+ from ctypes import c_char_p\r
+-from notmuch.globals import nmlib, STATUS, NotmuchError\r
++from notmuch.globals import (nmlib, STATUS, NotmuchError,\r
++ NotmuchFilenamesP, NotmuchMessagesP, NotmuchMessageP)\r
+ \r
+ \r
+ class Filenames(object):\r
+@@ -50,6 +51,7 @@ class Filenames(object):\r
+ \r
+ #notmuch_filenames_get\r
+ _get = nmlib.notmuch_filenames_get\r
++ _get.argtypes = [NotmuchFilenamesP]\r
+ _get.restype = c_char_p\r
+ \r
+ def __init__(self, files_p, parent):\r
+@@ -74,6 +76,14 @@ class Filenames(object):\r
+ #save reference to parent object so we keep it alive\r
+ self._parent = parent\r
+ \r
++ _valid = nmlib.notmuch_filenames_valid\r
++ _valid.argtypes = [NotmuchFilenamesP]\r
++ _valid.restype = bool\r
++\r
++ _move_to_next = nmlib.notmuch_filenames_move_to_next\r
++ _move_to_next.argtypes = [NotmuchFilenamesP]\r
++ _move_to_next.restype = None\r
++\r
+ def as_generator(self):\r
+ """Return generator of Filenames\r
+ \r
+@@ -82,9 +92,9 @@ class Filenames(object):\r
+ if self._files is None:\r
+ raise NotmuchError(STATUS.NOT_INITIALIZED)\r
+ \r
+- while nmlib.notmuch_filenames_valid(self._files):\r
++ while self._valid(self._files):\r
+ yield Filenames._get(self._files)\r
+- nmlib.notmuch_filenames_move_to_next(self._files)\r
++ self._move_to_next(self._files)\r
+ \r
+ self._files = None\r
+ \r
+@@ -101,7 +111,11 @@ class Filenames(object):\r
+ """\r
+ return "\n".join(self)\r
+ \r
++ _destroy = nmlib.notmuch_filenames_destroy\r
++ _destroy.argtypes = [NotmuchMessageP]\r
++ _destroy.restype = None\r
++\r
+ def __del__(self):\r
+ """Close and free the notmuch filenames"""\r
+ if self._files is not None:\r
+- nmlib.notmuch_filenames_destroy(self._files)\r
++ self._destroy(self._files)\r
+diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py\r
+index 4bf90c2..e0c7eda 100644\r
+--- a/bindings/python/notmuch/message.py\r
++++ b/bindings/python/notmuch/message.py\r
+@@ -21,7 +21,8 @@ Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'\r
+ \r
+ from ctypes import c_char_p, c_void_p, c_long, c_uint, c_int\r
+ from datetime import date\r
+-from notmuch.globals import nmlib, STATUS, NotmuchError, Enum, _str\r
++from notmuch.globals import (nmlib, STATUS, NotmuchError, Enum, _str,\r
++ NotmuchTagsP, NotmuchMessagesP, NotmuchMessageP, NotmuchFilenamesP)\r
+ from notmuch.tag import Tags\r
+ from notmuch.filename import Filenames\r
+ import sys\r
+@@ -92,10 +93,12 @@ class Messages(object):\r
+ \r
+ #notmuch_messages_get\r
+ _get = nmlib.notmuch_messages_get\r
+- _get.restype = c_void_p\r
++ _get.argtypes = [NotmuchMessagesP]\r
++ _get.restype = NotmuchMessageP\r
+ \r
+ _collect_tags = nmlib.notmuch_messages_collect_tags\r
+- _collect_tags.restype = c_void_p\r
++ _collect_tags.argtypes = [NotmuchMessagesP]\r
++ _collect_tags.restype = NotmuchTagsP\r
+ \r
+ def __init__(self, msgs_p, parent=None):\r
+ """\r
+@@ -146,16 +149,24 @@ class Messages(object):\r
+ """ Make Messages an iterator """\r
+ return self\r
+ \r
++ _valid = nmlib.notmuch_messages_valid\r
++ _valid.argtypes = [NotmuchMessagesP]\r
++ _valid.restype = bool\r
++\r
++ _move_to_next = nmlib.notmuch_messages_move_to_next\r
++ _move_to_next.argtypes = [NotmuchMessagesP]\r
++ _move_to_next.restype = None\r
++\r
+ def next(self):\r
+ if self._msgs is None:\r
+ raise NotmuchError(STATUS.NOT_INITIALIZED)\r
+ \r
+- if not nmlib.notmuch_messages_valid(self._msgs):\r
++ if not self._valid(self._msgs):\r
+ self._msgs = None\r
+ raise StopIteration\r
+ \r
+ msg = Message(Messages._get(self._msgs), self)\r
+- nmlib.notmuch_messages_move_to_next(self._msgs)\r
++ self._move_to_next(self._msgs)\r
+ return msg\r
+ \r
+ def __nonzero__(self):\r
+@@ -163,12 +174,16 @@ class Messages(object):\r
+ :return: True if there is at least one more thread in the\r
+ Iterator, False if not."""\r
+ return self._msgs is not None and \\r
+- nmlib.notmuch_messages_valid(self._msgs) > 0\r
++ self._valid(self._msgs) > 0\r
++\r
++ _destroy = nmlib.notmuch_messages_destroy\r
++ _destroy.argtypes = [NotmuchMessagesP]\r
++ _destroy.restype = None\r
+ \r
+ def __del__(self):\r
+ """Close and free the notmuch Messages"""\r
+ if self._msgs is not None:\r
+- nmlib.notmuch_messages_destroy(self._msgs)\r
++ self._destroy(self._msgs)\r
+ \r
+ def print_messages(self, format, indent=0, entire_thread=False):\r
+ """Outputs messages as needed for 'notmuch show' to sys.stdout\r
+@@ -235,44 +250,60 @@ class Message(object):\r
+ \r
+ """notmuch_message_get_filename (notmuch_message_t *message)"""\r
+ _get_filename = nmlib.notmuch_message_get_filename\r
++ _get_filename.argtypes = [NotmuchMessageP]\r
+ _get_filename.restype = c_char_p\r
+ \r
+ """return all filenames for a message"""\r
+ _get_filenames = nmlib.notmuch_message_get_filenames\r
+- _get_filenames.restype = c_void_p\r
++ _get_filenames.argtypes = [NotmuchMessageP]\r
++ _get_filenames.restype = NotmuchFilenamesP\r
+ \r
+ """notmuch_message_get_flag"""\r
+ _get_flag = nmlib.notmuch_message_get_flag\r
+- _get_flag.restype = c_uint\r
++ _get_flag.argtypes = [NotmuchMessageP, c_uint]\r
++ _get_flag.restype = bool\r
++\r
++ """notmuch_message_set_flag"""\r
++ _set_flag = nmlib.notmuch_message_set_flag\r
++ _set_flag.argtypes = [NotmuchMessageP, c_uint, c_int]\r
++ _set_flag.restype = None\r
+ \r
+ """notmuch_message_get_message_id (notmuch_message_t *message)"""\r
+ _get_message_id = nmlib.notmuch_message_get_message_id\r
++ _get_message_id.argtypes = [NotmuchMessageP]\r
+ _get_message_id.restype = c_char_p\r
+ \r
+ """notmuch_message_get_thread_id"""\r
+ _get_thread_id = nmlib.notmuch_message_get_thread_id\r
++ _get_thread_id.argtypes = [NotmuchMessageP]\r
+ _get_thread_id.restype = c_char_p\r
+ \r
+ """notmuch_message_get_replies"""\r
+ _get_replies = nmlib.notmuch_message_get_replies\r
+- _get_replies.restype = c_void_p\r
++ _get_replies.argtypes = [NotmuchMessageP]\r
++ _get_replies.restype = NotmuchMessagesP\r
+ \r
+ """notmuch_message_get_tags (notmuch_message_t *message)"""\r
+ _get_tags = nmlib.notmuch_message_get_tags\r
+- _get_tags.restype = c_void_p\r
++ _get_tags.argtypes = [NotmuchMessageP]\r
++ _get_tags.restype = NotmuchTagsP\r
+ \r
+ _get_date = nmlib.notmuch_message_get_date\r
++ _get_date.argtypes = [NotmuchMessageP]\r
+ _get_date.restype = c_long\r
+ \r
+ _get_header = nmlib.notmuch_message_get_header\r
++ _get_header.argtypes = [NotmuchMessageP, c_char_p]\r
+ _get_header.restype = c_char_p\r
+ \r
+ """notmuch_status_t ..._maildir_flags_to_tags (notmuch_message_t *)"""\r
+ _tags_to_maildir_flags = nmlib.notmuch_message_tags_to_maildir_flags\r
++ _tags_to_maildir_flags.argtypes = [NotmuchMessageP]\r
+ _tags_to_maildir_flags.restype = c_int\r
+ \r
+ """notmuch_status_t ..._tags_to_maildir_flags (notmuch_message_t *)"""\r
+ _maildir_flags_to_tags = nmlib.notmuch_message_maildir_flags_to_tags\r
++ _maildir_flags_to_tags.argtypes = [NotmuchMessageP]\r
+ _maildir_flags_to_tags.restype = c_int\r
+ \r
+ #Constants: Flags that can be set/get with set_flag\r
+@@ -450,7 +481,7 @@ class Message(object):\r
+ """\r
+ if self._msg is None:\r
+ raise NotmuchError(STATUS.NOT_INITIALIZED)\r
+- nmlib.notmuch_message_set_flag(self._msg, flag, value)\r
++ self._set_flag(self._msg, flag, value)\r
+ \r
+ def get_tags(self):\r
+ """Returns the message tags\r
+@@ -470,6 +501,10 @@ class Message(object):\r
+ raise NotmuchError(STATUS.NULL_POINTER)\r
+ return Tags(tags_p, self)\r
+ \r
++ _add_tag = nmlib.notmuch_message_add_tag\r
++ _add_tag.argtypes = [NotmuchMessageP, c_char_p]\r
++ _add_tag.restype = c_uint\r
++\r
+ def add_tag(self, tag, sync_maildir_flags=False):\r
+ """Adds a tag to the given message\r
+ \r
+@@ -504,7 +539,7 @@ class Message(object):\r
+ if self._msg is None:\r
+ raise NotmuchError(STATUS.NOT_INITIALIZED)\r
+ \r
+- status = nmlib.notmuch_message_add_tag(self._msg, _str(tag))\r
++ status = self._add_tag(self._msg, _str(tag))\r
+ \r
+ # bail out on failure\r
+ if status != STATUS.SUCCESS:\r
+@@ -514,6 +549,10 @@ class Message(object):\r
+ self.tags_to_maildir_flags()\r
+ return STATUS.SUCCESS\r
+ \r
++ _remove_tag = nmlib.notmuch_message_remove_tag\r
++ _remove_tag.argtypes = [NotmuchMessageP, c_char_p]\r
++ _remove_tag.restype = c_uint\r
++\r
+ def remove_tag(self, tag, sync_maildir_flags=False):\r
+ """Removes a tag from the given message\r
+ \r
+@@ -548,7 +587,7 @@ class Message(object):\r
+ if self._msg is None:\r
+ raise NotmuchError(STATUS.NOT_INITIALIZED)\r
+ \r
+- status = nmlib.notmuch_message_remove_tag(self._msg, _str(tag))\r
++ status = self._remove_tag(self._msg, _str(tag))\r
+ # bail out on error\r
+ if status != STATUS.SUCCESS:\r
+ raise NotmuchError(status)\r
+@@ -557,6 +596,10 @@ class Message(object):\r
+ self.tags_to_maildir_flags()\r
+ return STATUS.SUCCESS\r
+ \r
++ _remove_all_tags = nmlib.notmuch_message_remove_all_tags\r
++ _remove_all_tags.argtypes = [NotmuchMessageP]\r
++ _remove_all_tags.restype = c_uint\r
++\r
+ def remove_all_tags(self, sync_maildir_flags=False):\r
+ """Removes all tags from the given message.\r
+ \r
+@@ -585,7 +628,7 @@ class Message(object):\r
+ if self._msg is None:\r
+ raise NotmuchError(STATUS.NOT_INITIALIZED)\r
+ \r
+- status = nmlib.notmuch_message_remove_all_tags(self._msg)\r
++ status = self._remove_all_tags(self._msg)\r
+ \r
+ # bail out on error\r
+ if status != STATUS.SUCCESS:\r
+@@ -595,6 +638,10 @@ class Message(object):\r
+ self.tags_to_maildir_flags()\r
+ return STATUS.SUCCESS\r
+ \r
++ _freeze = nmlib.notmuch_message_freeze\r
++ _freeze.argtypes = [NotmuchMessageP]\r
++ _freeze.restype = c_uint\r
++\r
+ def freeze(self):\r
+ """Freezes the current state of 'message' within the database\r
+ \r
+@@ -639,7 +686,7 @@ class Message(object):\r
+ if self._msg is None:\r
+ raise NotmuchError(STATUS.NOT_INITIALIZED)\r
+ \r
+- status = nmlib.notmuch_message_freeze(self._msg)\r
++ status = self._freeze(self._msg)\r
+ \r
+ if STATUS.SUCCESS == status:\r
+ # return on success\r
+@@ -647,6 +694,10 @@ class Message(object):\r
+ \r
+ raise NotmuchError(status)\r
+ \r
++ _thaw = nmlib.notmuch_message_thaw\r
++ _thaw.argtypes = [NotmuchMessageP]\r
++ _thaw.restype = c_uint\r
++\r
+ def thaw(self):\r
+ """Thaws the current 'message'\r
+ \r
+@@ -674,7 +725,7 @@ class Message(object):\r
+ if self._msg is None:\r
+ raise NotmuchError(STATUS.NOT_INITIALIZED)\r
+ \r
+- status = nmlib.notmuch_message_thaw(self._msg)\r
++ status = self._thaw(self._msg)\r
+ \r
+ if STATUS.SUCCESS == status:\r
+ # return on success\r
+@@ -896,7 +947,11 @@ class Message(object):\r
+ res = cmp(list(self.get_filenames()), list(other.get_filenames()))\r
+ return res\r
+ \r
++ _destroy = nmlib.notmuch_message_destroy\r
++ _destroy.argtypes = [NotmuchMessageP]\r
++ _destroy.restype = None\r
++\r
+ def __del__(self):\r
+ """Close and free the notmuch Message"""\r
+ if self._msg is not None:\r
+- nmlib.notmuch_message_destroy(self._msg)\r
++ self._destroy(self._msg)\r
+diff --git a/bindings/python/notmuch/tag.py b/bindings/python/notmuch/tag.py\r
+index 50e3686..f3a3d27 100644\r
+--- a/bindings/python/notmuch/tag.py\r
++++ b/bindings/python/notmuch/tag.py\r
+@@ -17,7 +17,7 @@ along with notmuch. If not, see <http://www.gnu.org/licenses/>.\r
+ Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'\r
+ """\r
+ from ctypes import c_char_p\r
+-from notmuch.globals import nmlib, STATUS, NotmuchError\r
++from notmuch.globals import nmlib, STATUS, NotmuchError, NotmuchTagsP\r
+ \r
+ \r
+ class Tags(object):\r
+@@ -50,6 +50,7 @@ class Tags(object):\r
+ \r
+ #notmuch_tags_get\r
+ _get = nmlib.notmuch_tags_get\r
++ _get.argtypes = [NotmuchTagsP]\r
+ _get.restype = c_char_p\r
+ \r
+ def __init__(self, tags_p, parent=None):\r
+@@ -80,14 +81,22 @@ class Tags(object):\r
+ """ Make Tags an iterator """\r
+ return self\r
+ \r
++ _valid = nmlib.notmuch_tags_valid\r
++ _valid.argtypes = [NotmuchTagsP]\r
++ _valid.restype = bool\r
++\r
++ _move_to_next = nmlib.notmuch_tags_move_to_next\r
++ _move_to_next.argtypes = [NotmuchTagsP]\r
++ _move_to_next.restype = None\r
++\r
+ def next(self):\r
+ if self._tags is None:\r
+ raise NotmuchError(STATUS.NOT_INITIALIZED)\r
+- if not nmlib.notmuch_tags_valid(self._tags):\r
++ if not self._valid(self._tags):\r
+ self._tags = None\r
+ raise StopIteration\r
+ tag = Tags._get(self._tags).decode('UTF-8')\r
+- nmlib.notmuch_tags_move_to_next(self._tags)\r
++ self._move_to_next(self._tags)\r
+ return tag\r
+ \r
+ def __nonzero__(self):\r
+@@ -99,7 +108,7 @@ class Tags(object):\r
+ \r
+ :returns: True if the Tags() iterator has at least one more Tag\r
+ left."""\r
+- return nmlib.notmuch_tags_valid(self._tags) > 0\r
++ return self._valid(self._tags) > 0\r
+ \r
+ def __str__(self):\r
+ """The str() representation of Tags() is a space separated list of tags\r
+@@ -112,7 +121,11 @@ class Tags(object):\r
+ """\r
+ return " ".join(self)\r
+ \r
++ _destroy = nmlib.notmuch_tags_destroy\r
++ _destroy.argtypes = [NotmuchTagsP]\r
++ _destroy.restype = None\r
++\r
+ def __del__(self):\r
+ """Close and free the notmuch tags"""\r
+ if self._tags is not None:\r
+- nmlib.notmuch_tags_destroy(self._tags)\r
++ self._destroy(self._tags)\r
+diff --git a/bindings/python/notmuch/thread.py b/bindings/python/notmuch/thread.py\r
+index 5e08eb3..d903c76 100644\r
+--- a/bindings/python/notmuch/thread.py\r
++++ b/bindings/python/notmuch/thread.py\r
+@@ -17,8 +17,10 @@ along with notmuch. If not, see <http://www.gnu.org/licenses/>.\r
+ Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>'\r
+ """\r
+ \r
+-from ctypes import c_char_p, c_void_p, c_long\r
+-from notmuch.globals import nmlib, STATUS, NotmuchError\r
++from ctypes import c_char_p, c_void_p, c_long, c_int\r
++from notmuch.globals import (nmlib, STATUS,\r
++ NotmuchError, NotmuchThreadP, NotmuchThreadsP, NotmuchMessagesP,\r
++ NotmuchTagsP,)\r
+ from notmuch.message import Messages\r
+ from notmuch.tag import Tags\r
+ from datetime import date\r
+@@ -75,7 +77,8 @@ class Threads(object):\r
+ \r
+ #notmuch_threads_get\r
+ _get = nmlib.notmuch_threads_get\r
+- _get.restype = c_void_p\r
++ _get.argtypes = [NotmuchThreadsP]\r
++ _get.restype = NotmuchThreadP\r
+ \r
+ def __init__(self, threads_p, parent=None):\r
+ """\r
+@@ -105,16 +108,24 @@ class Threads(object):\r
+ """ Make Threads an iterator """\r
+ return self\r
+ \r
++ _valid = nmlib.notmuch_threads_valid\r
++ _valid.argtypes = [NotmuchThreadsP]\r
++ _valid.restype = bool\r
++\r
++ _move_to_next = nmlib.notmuch_threads_move_to_next\r
++ _move_to_next.argtypes = [NotmuchThreadsP]\r
++ _move_to_next.restype = None\r
++\r
+ def next(self):\r
+ if self._threads is None:\r
+ raise NotmuchError(STATUS.NOT_INITIALIZED)\r
+ \r
+- if not nmlib.notmuch_threads_valid(self._threads):\r
++ if not self._valid(self._threads):\r
+ self._threads = None\r
+ raise StopIteration\r
+ \r
+ thread = Thread(Threads._get(self._threads), self)\r
+- nmlib.notmuch_threads_move_to_next(self._threads)\r
++ self._move_to_next(self._threads)\r
+ return thread\r
+ \r
+ def __len__(self):\r
+@@ -134,8 +145,8 @@ class Threads(object):\r
+ \r
+ i = 0\r
+ # returns 'bool'. On out-of-memory it returns None\r
+- while nmlib.notmuch_threads_valid(self._threads):\r
+- nmlib.notmuch_threads_move_to_next(self._threads)\r
++ while self._valid(self._threads):\r
++ self._move_to_next(self._threads)\r
+ i += 1\r
+ # reset self._threads to mark as "exhausted"\r
+ self._threads = None\r
+@@ -153,12 +164,16 @@ class Threads(object):\r
+ Iterator, False if not. None on a "Out-of-memory" error.\r
+ """\r
+ return self._threads is not None and \\r
+- nmlib.notmuch_threads_valid(self._threads) > 0\r
++ self._valid(self._threads) > 0\r
++\r
++ _destroy = nmlib.notmuch_threads_destroy\r
++ _destroy.argtypes = [NotmuchThreadsP]\r
++ _destroy.argtypes = None\r
+ \r
+ def __del__(self):\r
+ """Close and free the notmuch Threads"""\r
+ if self._threads is not None:\r
+- nmlib.notmuch_messages_destroy(self._threads)\r
++ self._destroy(self._threads)\r
+ \r
+ \r
+ class Thread(object):\r
+@@ -166,29 +181,36 @@ class Thread(object):\r
+ \r
+ """notmuch_thread_get_thread_id"""\r
+ _get_thread_id = nmlib.notmuch_thread_get_thread_id\r
++ _get_thread_id.argtypes = [NotmuchThreadP]\r
+ _get_thread_id.restype = c_char_p\r
+ \r
+ """notmuch_thread_get_authors"""\r
+ _get_authors = nmlib.notmuch_thread_get_authors\r
++ _get_authors.argtypes = [NotmuchThreadP]\r
+ _get_authors.restype = c_char_p\r
+ \r
+ """notmuch_thread_get_subject"""\r
+ _get_subject = nmlib.notmuch_thread_get_subject\r
++ _get_subject.argtypes = [NotmuchThreadP]\r
+ _get_subject.restype = c_char_p\r
+ \r
+ """notmuch_thread_get_toplevel_messages"""\r
+ _get_toplevel_messages = nmlib.notmuch_thread_get_toplevel_messages\r
+- _get_toplevel_messages.restype = c_void_p\r
++ _get_toplevel_messages.argtypes = [NotmuchThreadP]\r
++ _get_toplevel_messages.restype = NotmuchMessagesP\r
+ \r
+ _get_newest_date = nmlib.notmuch_thread_get_newest_date\r
++ _get_newest_date.argtypes = [NotmuchThreadP]\r
+ _get_newest_date.restype = c_long\r
+ \r
+ _get_oldest_date = nmlib.notmuch_thread_get_oldest_date\r
++ _get_oldest_date.argtypes = [NotmuchThreadP]\r
+ _get_oldest_date.restype = c_long\r
+ \r
+ """notmuch_thread_get_tags"""\r
+ _get_tags = nmlib.notmuch_thread_get_tags\r
+- _get_tags.restype = c_void_p\r
++ _get_tags.argtypes = [NotmuchThreadP]\r
++ _get_tags.restype = NotmuchTagsP\r
+ \r
+ def __init__(self, thread_p, parent=None):\r
+ """\r
+@@ -225,6 +247,11 @@ class Thread(object):\r
+ raise NotmuchError(STATUS.NOT_INITIALIZED)\r
+ return Thread._get_thread_id(self._thread)\r
+ \r
++\r
++ _get_total_messages = nmlib.notmuch_thread_get_total_messages\r
++ _get_total_messages.argtypes = [NotmuchThreadP]\r
++ _get_total_messages.restype = c_int\r
++\r
+ def get_total_messages(self):\r
+ """Get the total number of messages in 'thread'\r
+ \r
+@@ -236,7 +263,7 @@ class Thread(object):\r
+ """\r
+ if self._thread is None:\r
+ raise NotmuchError(STATUS.NOT_INITIALIZED)\r
+- return nmlib.notmuch_thread_get_total_messages(self._thread)\r
++ return self._get_total_messages(self._thread)\r
+ \r
+ def get_toplevel_messages(self):\r
+ """Returns a :class:`Messages` iterator for the top-level messages in\r
+@@ -267,6 +294,10 @@ class Thread(object):\r
+ \r
+ return Messages(msgs_p, self)\r
+ \r
++ _get_matched_messages = nmlib.notmuch_thread_get_matched_messages\r
++ _get_matched_messages.argtypes = [NotmuchThreadP]\r
++ _get_matched_messages.restype = c_int\r
++\r
+ def get_matched_messages(self):\r
+ """Returns the number of messages in 'thread' that matched the query\r
+ \r
+@@ -278,7 +309,7 @@ class Thread(object):\r
+ """\r
+ if self._thread is None:\r
+ raise NotmuchError(STATUS.NOT_INITIALIZED)\r
+- return nmlib.notmuch_thread_get_matched_messages(self._thread)\r
++ return self._get_matched_messages(self._thread)\r
+ \r
+ def get_authors(self):\r
+ """Returns the authors of 'thread'\r
+@@ -387,7 +418,11 @@ class Thread(object):\r
+ thread['subject'],\r
+ thread['tags'])\r
+ \r
++ _destroy = nmlib.notmuch_thread_destroy\r
++ _destroy.argtypes = [NotmuchThreadP]\r
++ _destroy.restype = None\r
++\r
+ def __del__(self):\r
+ """Close and free the notmuch Thread"""\r
+ if self._thread is not None:\r
+- nmlib.notmuch_thread_destroy(self._thread)\r
++ self._destroy(self._thread)\r
+-- \r
+1.7.6.3\r
+\r