From 8e7a108363574ad3a342ed33a7c61c7dea65dc8a Mon Sep 17 00:00:00 2001 From: Martin Owens Date: Fri, 16 Sep 2011 13:19:14 +0200 Subject: [PATCH] python: Ensure that we pass utf-8 encoded string to libnotmuch If we use unicode objects, libnotmuch would not cope with null bytes in the byte array, so we need to make sure they are nicely formatted as utf-8. Introduce a helper function _str which does this throughout the code. Patch slightly modified by Sebastian Spaeth. Signed-off-by: Sebastian Spaeth --- bindings/python/notmuch/database.py | 29 +++++++++-------------------- bindings/python/notmuch/globals.py | 12 ++++++++++++ bindings/python/notmuch/message.py | 6 +++--- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index f18ca148..dc124f5e 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -19,12 +19,11 @@ Copyright 2010 Sebastian Spaeth ' import os from ctypes import c_int, c_char_p, c_void_p, c_uint, c_long, byref -from notmuch.globals import nmlib, STATUS, NotmuchError, Enum +from notmuch.globals import nmlib, STATUS, NotmuchError, Enum, _str from notmuch.thread import Threads from notmuch.message import Messages, Message from notmuch.tag import Tags - class Database(object): """Represents a notmuch database (wraps notmuch_database_t) @@ -101,7 +100,6 @@ class Database(object): Database._std_db_path = self._get_user_default_db() path = Database._std_db_path - assert isinstance(path, basestring), 'Path must be a string or None.' if create == False: self.open(path, mode) else: @@ -132,7 +130,7 @@ class Database(object): raise NotmuchError(message="Cannot create db, this Database() " "already has an open one.") - res = Database._create(path, Database.MODE.READ_WRITE) + res = Database._create(_str(path), Database.MODE.READ_WRITE) if res is None: raise NotmuchError( @@ -152,9 +150,7 @@ class Database(object): :exception: Raises :exc:`NotmuchError` in case of any failure (after printing an error message on stderr). """ - if isinstance(path, unicode): - path = path.encode('utf-8') - res = Database._open(path, mode) + res = Database._open(_str(path), mode) if res is None: raise NotmuchError( @@ -259,12 +255,10 @@ class Database(object): #we got a relative path, make it absolute abs_dirpath = os.path.abspath(os.path.join(self.get_path(), path)) - if isinstance(path, unicode): - path = path.encode('UTF-8') - dir_p = Database._get_directory(self._db, path) + dir_p = Database._get_directory(self._db, _str(path)) # return the Directory, init it with the absolute path - return Directory(abs_dirpath, dir_p, self) + return Directory(_str(abs_dirpath), dir_p, self) def add_message(self, filename, sync_maildir_flags=False): """Adds a new message to the database @@ -321,7 +315,7 @@ class Database(object): msg_p = c_void_p() status = nmlib.notmuch_database_add_message(self._db, - filename, + _str(filename), byref(msg_p)) if not status in [STATUS.SUCCESS, STATUS.DUPLICATE_MESSAGE_ID]: @@ -390,10 +384,8 @@ class Database(object): # Raise a NotmuchError if not initialized self._verify_initialized_db() - msg_p = Database._find_message(self._db, msgid) - if msg_p is None: - return None - return Message(msg_p, self) + msg_p = Database._find_message(self._db, _str(msgid)) + return msg_p and Message(msg_p, self) or None def get_all_tags(self): """Returns :class:`Tags` with a list of all tags found in the database @@ -535,11 +527,8 @@ class Query(object): raise NotmuchError(STATUS.NOT_INITIALIZED) # create reference to parent db to keep it alive self._db = db - if isinstance(querystr, unicode): - # xapian takes utf-8 encoded byte arrays - querystr = querystr.encode('utf-8') # create query, return None if too little mem available - query_p = Query._create(db.db_p, querystr) + query_p = Query._create(db.db_p, _str(querystr)) if query_p is None: NotmuchError(STATUS.NULL_POINTER) self._query = query_p diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py index 77f2905b..05b9962a 100644 --- a/bindings/python/notmuch/globals.py +++ b/bindings/python/notmuch/globals.py @@ -98,3 +98,15 @@ class NotmuchError(Exception): return self.args[0] else: return STATUS.status2str(self.args[1]) + +def _str(value): + """Ensure a nicely utf-8 encoded string to pass to libnotmuch + + C++ code expects strings to be well formatted and + unicode strings to have no null bytes.""" + if not isinstance(value, basestring): + raise TypeError("Expected str or unicode, got %s" % str(type(value))) + if isinstance(value, unicode): + return value.encode('UTF-8') + return value + diff --git a/bindings/python/notmuch/message.py b/bindings/python/notmuch/message.py index ae6ae1b1..4f93a2a4 100644 --- a/bindings/python/notmuch/message.py +++ b/bindings/python/notmuch/message.py @@ -21,7 +21,7 @@ Copyright 2010 Sebastian Spaeth ' from ctypes import c_char_p, c_void_p, c_long, c_uint, c_int from datetime import date -from notmuch.globals import nmlib, STATUS, NotmuchError, Enum +from notmuch.globals import nmlib, STATUS, NotmuchError, Enum, _str from notmuch.tag import Tags from notmuch.filename import Filenames import sys @@ -505,7 +505,7 @@ class Message(object): if self._msg is None: raise NotmuchError(STATUS.NOT_INITIALIZED) - status = nmlib.notmuch_message_add_tag(self._msg, tag) + status = nmlib.notmuch_message_add_tag(self._msg, _str(tag)) # bail out on failure if status != STATUS.SUCCESS: @@ -549,7 +549,7 @@ class Message(object): if self._msg is None: raise NotmuchError(STATUS.NOT_INITIALIZED) - status = nmlib.notmuch_message_remove_tag(self._msg, tag) + status = nmlib.notmuch_message_remove_tag(self._msg, _str(tag)) # bail out on error if status != STATUS.SUCCESS: raise NotmuchError(status)