/* message-property.cc - Properties are like tags, but (key,value) pairs. * keys are allowed to repeat. * * This file is part of notmuch. * * Copyright © 2016 David Bremner * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/ . * * Author: David Bremner */ #include "notmuch-private.h" #include "database-private.h" #include "message-private.h" struct _notmuch_message_property_list { Xapian::TermIterator *iterator; notmuch_message_t *message; const char *prefix; char *current; }; static int _notmuch_message_property_list_destroy (notmuch_message_property_list_t *list) { delete list->iterator; return 0; } notmuch_status_t notmuch_message_get_property (notmuch_message_t *message, const char *key, const char **value) { notmuch_private_status_t private_status; char *term = NULL; if (! value) return NOTMUCH_STATUS_NULL_POINTER; term = talloc_asprintf (message, "%s%s=", _find_prefix ("property"), key); if (term == NULL) { private_status = NOTMUCH_PRIVATE_STATUS_OUT_OF_MEMORY; goto DONE; } private_status = _notmuch_message_get_prefixed_term (message, term, value); if (private_status == NOTMUCH_PRIVATE_STATUS_NO_TERM_FOUND) { *value = NULL; private_status = NOTMUCH_PRIVATE_STATUS_SUCCESS; } DONE: if (term) talloc_free (term); if (private_status) return COERCE_STATUS (private_status, "Unhandled error retrieving message property"); return NOTMUCH_STATUS_SUCCESS; } static notmuch_status_t _notmuch_message_modify_property (notmuch_message_t *message, const char *key, const char *value, notmuch_bool_t delete_it) { notmuch_private_status_t private_status; notmuch_status_t status; char *term = NULL; status = _notmuch_database_ensure_writable (_notmuch_message_database (message)); if (status) return status; if (key == NULL || value== NULL) return NOTMUCH_STATUS_NULL_POINTER; if (index (key, '=') || index (value, '=')) return NOTMUCH_STATUS_ILLEGAL_ARGUMENT; term = talloc_asprintf (message, "%s=%s", key, value); /* this invalidates all of the property, which it currently shouldn't */ if (delete_it) private_status = _notmuch_message_remove_term (message, "property", term); else private_status = _notmuch_message_add_term (message, "property", term); if (private_status) return COERCE_STATUS (private_status, "Unhandled error modifying message property"); _notmuch_message_sync (message); if (term) talloc_free (term); return NOTMUCH_STATUS_SUCCESS; } notmuch_status_t notmuch_message_add_property (notmuch_message_t *message, const char *key, const char *value) { return _notmuch_message_modify_property (message, key, value, FALSE); } notmuch_status_t notmuch_message_remove_property (notmuch_message_t *message, const char *key, const char *value) { return _notmuch_message_modify_property (message, key, value, TRUE); } notmuch_status_t notmuch_message_get_property_list (notmuch_message_t *message, const char *key, notmuch_message_property_list_t **out) { notmuch_message_property_list_t *list = NULL; notmuch_status_t status = NOTMUCH_STATUS_SUCCESS; notmuch_database_t *notmuch = _notmuch_message_database (message); const char *term; list = talloc (message, notmuch_message_property_list_t); if (! list) { status = NOTMUCH_STATUS_OUT_OF_MEMORY; goto DONE; } talloc_set_destructor (list, _notmuch_message_property_list_destroy); list->current = NULL; list->message = message; term = talloc_asprintf (message, "%s%s=", _find_prefix ("property"), key); list->prefix = talloc_strdup (list, term); if (term == NULL) { status = NOTMUCH_STATUS_OUT_OF_MEMORY; goto DONE; } try { /* force copying onto the heap */ list->iterator = new Xapian::TermIterator; *list->iterator = message->doc.termlist_begin (); (*list->iterator).skip_to (term); } catch (const Xapian::Error &error) { _notmuch_database_log (notmuch, "A Xapian exception occurred getting property iterator: %s.\n", error.get_msg().c_str()); notmuch->exception_reported = TRUE; status = NOTMUCH_STATUS_XAPIAN_EXCEPTION; } *out = list; DONE: if (status && list) talloc_free (list); return status; } notmuch_bool_t notmuch_message_property_list_valid (notmuch_message_property_list_t *list) { if (*(list->iterator) == list->message->doc.termlist_end ()) return FALSE; if (strncmp (list->prefix, (**list->iterator).c_str (), strlen(list->prefix)) != 0) return FALSE; return TRUE; } const char * notmuch_message_property_list_value (notmuch_message_property_list_t *list) { if (list->current) talloc_free (list->current); list->current = talloc_strdup (list, (**list->iterator).c_str () + strlen (list->prefix)); return list->current; } void notmuch_message_property_list_move_to_next (notmuch_message_property_list_t *list) { (*(list->iterator))++; } void notmuch_message_property_list_destroy (notmuch_message_property_list_t *list) { talloc_free (list); }