1 // Wrapper around the notmuch library
6 #cgo LDFLAGS: -lnotmuch
16 // Status codes used for the return values of most functions
17 type Status C.notmuch_status_t
20 STATUS_SUCCESS Status = iota
22 STATUS_READ_ONLY_DATABASE
23 STATUS_XAPIAN_EXCEPTION
26 STATUS_DUPLICATE_MESSAGE_ID
29 STATUS_UNBALANCED_FREEZE_THAW
30 STATUS_UNBALANCED_ATOMIC
35 func (self Status) String() string {
39 p = C.notmuch_status_to_string(C.notmuch_status_t(self))
47 /* Various opaque data types. For each notmuch_<foo>_t see the various
48 * notmuch_<foo> functions below. */
50 type Database struct {
51 db *C.notmuch_database_t
55 query *C.notmuch_query_t
59 threads *C.notmuch_threads_t
63 thread *C.notmuch_thread_t
66 type Messages struct {
67 messages *C.notmuch_messages_t
71 message *C.notmuch_message_t
75 tags *C.notmuch_tags_t
78 type Directory struct {
79 dir *C.notmuch_directory_t
82 type Filenames struct {
83 fnames *C.notmuch_filenames_t
86 type DatabaseMode C.notmuch_database_mode_t
89 DATABASE_MODE_READ_ONLY DatabaseMode = 0
90 DATABASE_MODE_READ_WRITE
93 // Create a new, empty notmuch database located at 'path'
94 func NewDatabase(path string) (*Database, Status) {
96 var c_path *C.char = C.CString(path)
97 defer C.free(unsafe.Pointer(c_path))
100 return nil, STATUS_OUT_OF_MEMORY
103 self := &Database{db: nil}
104 st := Status(C.notmuch_database_create(c_path, &self.db))
105 if st != STATUS_SUCCESS {
111 /* Open an existing notmuch database located at 'path'.
113 * The database should have been created at some time in the past,
114 * (not necessarily by this process), by calling
115 * notmuch_database_create with 'path'. By default the database should be
116 * opened for reading only. In order to write to the database you need to
117 * pass the NOTMUCH_DATABASE_MODE_READ_WRITE mode.
119 * An existing notmuch database can be identified by the presence of a
120 * directory named ".notmuch" below 'path'.
122 * The caller should call notmuch_database_destroy when finished with
125 * In case of any failure, this function returns NULL, (after printing
126 * an error message on stderr).
128 func OpenDatabase(path string, mode DatabaseMode) (*Database, Status) {
130 var c_path *C.char = C.CString(path)
131 defer C.free(unsafe.Pointer(c_path))
134 return nil, STATUS_OUT_OF_MEMORY
137 self := &Database{db: nil}
138 st := Status(C.notmuch_database_open(c_path, C.notmuch_database_mode_t(mode), &self.db))
139 if st != STATUS_SUCCESS {
145 /* Close the given notmuch database, freeing all associated
146 * resources. See notmuch_database_open. */
147 func (self *Database) Close() {
148 C.notmuch_database_destroy(self.db)
151 /* Return the database path of the given database.
153 func (self *Database) GetPath() string {
155 /* The return value is a string owned by notmuch so should not be
156 * modified nor freed by the caller. */
157 var p *C.char = C.notmuch_database_get_path(self.db)
165 /* Return the database format version of the given database. */
166 func (self *Database) GetVersion() uint {
167 return uint(C.notmuch_database_get_version(self.db))
170 /* Does this database need to be upgraded before writing to it?
172 * If this function returns TRUE then no functions that modify the
173 * database (notmuch_database_add_message, notmuch_message_add_tag,
174 * notmuch_directory_set_mtime, etc.) will work unless the function
175 * notmuch_database_upgrade is called successfully first. */
176 func (self *Database) NeedsUpgrade() bool {
177 do_upgrade := C.notmuch_database_needs_upgrade(self.db)
184 // TODO: notmuch_database_upgrade
186 /* Retrieve a directory object from the database for 'path'.
188 * Here, 'path' should be a path relative to the path of 'database'
189 * (see notmuch_database_get_path), or else should be an absolute path
190 * with initial components that match the path of 'database'.
192 * Can return NULL if a Xapian exception occurs.
194 func (self *Database) GetDirectory(path string) *Directory {
195 var c_path *C.char = C.CString(path)
196 defer C.free(unsafe.Pointer(c_path))
202 c_dir := C.notmuch_database_get_directory(self.db, c_path)
206 return &Directory{dir: c_dir}
209 /* Add a new message to the given notmuch database.
211 * Here,'filename' should be a path relative to the path of
212 * 'database' (see notmuch_database_get_path), or else should be an
213 * absolute filename with initial components that match the path of
216 * The file should be a single mail message (not a multi-message mbox)
217 * that is expected to remain at its current location, (since the
218 * notmuch database will reference the filename, and will not copy the
219 * entire contents of the file.
221 * If 'message' is not NULL, then, on successful return '*message'
222 * will be initialized to a message object that can be used for things
223 * such as adding tags to the just-added message. The user should call
224 * notmuch_message_destroy when done with the message. On any failure
225 * '*message' will be set to NULL.
229 * NOTMUCH_STATUS_SUCCESS: Message successfully added to database.
231 * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred,
234 * NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: Message has the same message
235 * ID as another message already in the database. The new
236 * filename was successfully added to the message in the database
237 * (if not already present).
239 * NOTMUCH_STATUS_FILE_ERROR: an error occurred trying to open the
240 * file, (such as permission denied, or file not found,
241 * etc.). Nothing added to the database.
243 * NOTMUCH_STATUS_FILE_NOT_EMAIL: the contents of filename don't look
244 * like an email message. Nothing added to the database.
246 * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only
247 * mode so no message can be added.
249 func (self *Database) AddMessage(fname string) (*Message, Status) {
250 var c_fname *C.char = C.CString(fname)
251 defer C.free(unsafe.Pointer(c_fname))
254 return nil, STATUS_OUT_OF_MEMORY
257 var c_msg *C.notmuch_message_t = new(C.notmuch_message_t)
258 st := Status(C.notmuch_database_add_message(self.db, c_fname, &c_msg))
260 return &Message{message: c_msg}, st
263 /* Remove a message from the given notmuch database.
265 * Note that only this particular filename association is removed from
266 * the database. If the same message (as determined by the message ID)
267 * is still available via other filenames, then the message will
268 * persist in the database for those filenames. When the last filename
269 * is removed for a particular message, the database content for that
270 * message will be entirely removed.
274 * NOTMUCH_STATUS_SUCCESS: The last filename was removed and the
275 * message was removed from the database.
277 * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred,
278 * message not removed.
280 * NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: This filename was removed but
281 * the message persists in the database with at least one other
284 * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only
285 * mode so no message can be removed.
287 func (self *Database) RemoveMessage(fname string) Status {
289 var c_fname *C.char = C.CString(fname)
290 defer C.free(unsafe.Pointer(c_fname))
293 return STATUS_OUT_OF_MEMORY
296 st := C.notmuch_database_remove_message(self.db, c_fname)
300 /* Find a message with the given message_id.
302 * If the database contains a message with the given message_id, then
303 * a new notmuch_message_t object is returned. The caller should call
304 * notmuch_message_destroy when done with the message.
306 * This function returns NULL in the following situations:
308 * * No message is found with the given message_id
309 * * An out-of-memory situation occurs
310 * * A Xapian exception occurs
312 func (self *Database) FindMessage(message_id string) (*Message, Status) {
314 var c_msg_id *C.char = C.CString(message_id)
315 defer C.free(unsafe.Pointer(c_msg_id))
318 return nil, STATUS_OUT_OF_MEMORY
321 msg := &Message{message: nil}
322 st := Status(C.notmuch_database_find_message(self.db, c_msg_id, &msg.message))
323 if st != STATUS_SUCCESS {
329 /* Return a list of all tags found in the database.
331 * This function creates a list of all tags found in the database. The
332 * resulting list contains all tags from all messages found in the database.
334 * On error this function returns NULL.
336 func (self *Database) GetAllTags() *Tags {
337 tags := C.notmuch_database_get_all_tags(self.db)
341 return &Tags{tags: tags}
344 /* Create a new query for 'database'.
346 * Here, 'database' should be an open database, (see
347 * notmuch_database_open and notmuch_database_create).
349 * For the query string, we'll document the syntax here more
350 * completely in the future, but it's likely to be a specialized
351 * version of the general Xapian query syntax:
353 * http://xapian.org/docs/queryparser.html
355 * As a special case, passing either a length-zero string, (that is ""),
356 * or a string consisting of a single asterisk (that is "*"), will
357 * result in a query that returns all messages in the database.
359 * See notmuch_query_set_sort for controlling the order of results.
360 * See notmuch_query_search_messages and notmuch_query_search_threads
361 * to actually execute the query.
363 * User should call notmuch_query_destroy when finished with this
366 * Will return NULL if insufficient memory is available.
368 func (self *Database) CreateQuery(query string) *Query {
370 var c_query *C.char = C.CString(query)
371 defer C.free(unsafe.Pointer(c_query))
377 q := C.notmuch_query_create(self.db, c_query)
381 return &Query{query: q}
384 /* Sort values for notmuch_query_set_sort */
385 type Sort C.notmuch_sort_t
388 SORT_OLDEST_FIRST Sort = 0
394 /* Return the query_string of this query. See notmuch_query_create. */
395 func (self *Query) String() string {
396 // FIXME: do we own 'q' or not ?
397 q := C.notmuch_query_get_query_string(self.query)
398 //defer C.free(unsafe.Pointer(q))
408 /* Specify the sorting desired for this query. */
409 func (self *Query) SetSort(sort Sort) {
410 C.notmuch_query_set_sort(self.query, C.notmuch_sort_t(sort))
413 /* Return the sort specified for this query. See notmuch_query_set_sort. */
414 func (self *Query) GetSort() Sort {
415 return Sort(C.notmuch_query_get_sort(self.query))
418 /* Execute a query for threads, returning a notmuch_threads_t object
419 * which can be used to iterate over the results. The returned threads
420 * object is owned by the query and as such, will only be valid until
421 * notmuch_query_destroy.
423 * Typical usage might be:
425 * notmuch_query_t *query;
426 * notmuch_threads_t *threads;
427 * notmuch_thread_t *thread;
429 * query = notmuch_query_create (database, query_string);
431 * for (threads = notmuch_query_search_threads (query);
432 * notmuch_threads_valid (threads);
433 * notmuch_threads_move_to_next (threads))
435 * thread = notmuch_threads_get (threads);
437 * notmuch_thread_destroy (thread);
440 * notmuch_query_destroy (query);
442 * Note: If you are finished with a thread before its containing
443 * query, you can call notmuch_thread_destroy to clean up some memory
444 * sooner (as in the above example). Otherwise, if your thread objects
445 * are long-lived, then you don't need to call notmuch_thread_destroy
446 * and all the memory will still be reclaimed when the query is
449 * Note that there's no explicit destructor needed for the
450 * notmuch_threads_t object. (For consistency, we do provide a
451 * notmuch_threads_destroy function, but there's no good reason
452 * to call it if the query is about to be destroyed).
454 * If a Xapian exception occurs this function will return NULL.
456 func (self *Query) SearchThreads() *Threads {
457 threads := C.notmuch_query_search_threads(self.query)
461 return &Threads{threads: threads}
464 /* Execute a query for messages, returning a notmuch_messages_t object
465 * which can be used to iterate over the results. The returned
466 * messages object is owned by the query and as such, will only be
467 * valid until notmuch_query_destroy.
469 * Typical usage might be:
471 * notmuch_query_t *query;
472 * notmuch_messages_t *messages;
473 * notmuch_message_t *message;
475 * query = notmuch_query_create (database, query_string);
477 * for (messages = notmuch_query_search_messages (query);
478 * notmuch_messages_valid (messages);
479 * notmuch_messages_move_to_next (messages))
481 * message = notmuch_messages_get (messages);
483 * notmuch_message_destroy (message);
486 * notmuch_query_destroy (query);
488 * Note: If you are finished with a message before its containing
489 * query, you can call notmuch_message_destroy to clean up some memory
490 * sooner (as in the above example). Otherwise, if your message
491 * objects are long-lived, then you don't need to call
492 * notmuch_message_destroy and all the memory will still be reclaimed
493 * when the query is destroyed.
495 * Note that there's no explicit destructor needed for the
496 * notmuch_messages_t object. (For consistency, we do provide a
497 * notmuch_messages_destroy function, but there's no good
498 * reason to call it if the query is about to be destroyed).
500 * If a Xapian exception occurs this function will return NULL.
502 func (self *Query) SearchMessages() *Messages {
503 msgs := C.notmuch_query_search_messages(self.query)
507 return &Messages{messages: msgs}
510 /* Destroy a notmuch_query_t along with any associated resources.
512 * This will in turn destroy any notmuch_threads_t and
513 * notmuch_messages_t objects generated by this query, (and in
514 * turn any notmuch_thread_t and notmuch_message_t objects generated
515 * from those results, etc.), if such objects haven't already been
518 func (self *Query) Destroy() {
519 if self.query != nil {
520 C.notmuch_query_destroy(self.query)
524 /* Return an estimate of the number of messages matching a search
526 * This function performs a search and returns Xapian's best
527 * guess as to number of matching messages.
529 * If a Xapian exception occurs, this function may return 0 (after
530 * printing a message).
532 func (self *Query) CountMessages() uint {
533 return uint(C.notmuch_query_count_messages(self.query))
536 // TODO: wrap threads and thread
538 /* Is the given 'threads' iterator pointing at a valid thread.
540 * When this function returns TRUE, notmuch_threads_get will return a
541 * valid object. Whereas when this function returns FALSE,
542 * notmuch_threads_get will return NULL.
544 * See the documentation of notmuch_query_search_threads for example
545 * code showing how to iterate over a notmuch_threads_t object.
547 func (self *Threads) Valid() bool {
548 if self.threads == nil {
551 valid := C.notmuch_threads_valid(self.threads)
558 /* Destroy a notmuch_threads_t object.
560 * It's not strictly necessary to call this function. All memory from
561 * the notmuch_threads_t object will be reclaimed when the
562 * containg query object is destroyed.
564 func (self *Threads) Destroy() {
565 if self.threads != nil {
566 C.notmuch_threads_destroy(self.threads)
570 /* Is the given 'messages' iterator pointing at a valid message.
572 * When this function returns TRUE, notmuch_messages_get will return a
573 * valid object. Whereas when this function returns FALSE,
574 * notmuch_messages_get will return NULL.
576 * See the documentation of notmuch_query_search_messages for example
577 * code showing how to iterate over a notmuch_messages_t object.
579 func (self *Messages) Valid() bool {
580 if self.messages == nil {
583 valid := C.notmuch_messages_valid(self.messages)
590 /* Get the current message from 'messages' as a notmuch_message_t.
592 * Note: The returned message belongs to 'messages' and has a lifetime
593 * identical to it (and the query to which it belongs).
595 * See the documentation of notmuch_query_search_messages for example
596 * code showing how to iterate over a notmuch_messages_t object.
598 * If an out-of-memory situation occurs, this function will return
601 func (self *Messages) Get() *Message {
602 if self.messages == nil {
605 msg := C.notmuch_messages_get(self.messages)
609 return &Message{message: msg}
612 /* Move the 'messages' iterator to the next message.
614 * If 'messages' is already pointing at the last message then the
615 * iterator will be moved to a point just beyond that last message,
616 * (where notmuch_messages_valid will return FALSE and
617 * notmuch_messages_get will return NULL).
619 * See the documentation of notmuch_query_search_messages for example
620 * code showing how to iterate over a notmuch_messages_t object.
622 func (self *Messages) MoveToNext() {
623 if self.messages == nil {
626 C.notmuch_messages_move_to_next(self.messages)
629 /* Destroy a notmuch_messages_t object.
631 * It's not strictly necessary to call this function. All memory from
632 * the notmuch_messages_t object will be reclaimed when the containing
633 * query object is destroyed.
635 func (self *Messages) Destroy() {
636 if self.messages != nil {
637 C.notmuch_messages_destroy(self.messages)
641 /* Return a list of tags from all messages.
643 * The resulting list is guaranteed not to contain duplicated tags.
645 * WARNING: You can no longer iterate over messages after calling this
646 * function, because the iterator will point at the end of the list.
647 * We do not have a function to reset the iterator yet and the only
648 * way how you can iterate over the list again is to recreate the
651 * The function returns NULL on error.
653 func (self *Messages) CollectTags() *Tags {
654 if self.messages == nil {
657 tags := C.notmuch_messages_collect_tags(self.messages)
661 return &Tags{tags: tags}
664 /* Get the message ID of 'message'.
666 * The returned string belongs to 'message' and as such, should not be
667 * modified by the caller and will only be valid for as long as the
668 * message is valid, (which is until the query from which it derived
671 * This function will not return NULL since Notmuch ensures that every
672 * message has a unique message ID, (Notmuch will generate an ID for a
673 * message if the original file does not contain one).
675 func (self *Message) GetMessageId() string {
677 if self.message == nil {
680 id := C.notmuch_message_get_message_id(self.message)
682 // defer C.free(unsafe.Pointer(id))
686 return C.GoString(id)
689 /* Get the thread ID of 'message'.
691 * The returned string belongs to 'message' and as such, should not be
692 * modified by the caller and will only be valid for as long as the
693 * message is valid, (for example, until the user calls
694 * notmuch_message_destroy on 'message' or until a query from which it
695 * derived is destroyed).
697 * This function will not return NULL since Notmuch ensures that every
698 * message belongs to a single thread.
700 func (self *Message) GetThreadId() string {
702 if self.message == nil {
705 id := C.notmuch_message_get_thread_id(self.message)
707 // defer C.free(unsafe.Pointer(id))
713 return C.GoString(id)
716 /* Get a notmuch_messages_t iterator for all of the replies to
719 * Note: This call only makes sense if 'message' was ultimately
720 * obtained from a notmuch_thread_t object, (such as by coming
721 * directly from the result of calling notmuch_thread_get_
722 * toplevel_messages or by any number of subsequent
723 * calls to notmuch_message_get_replies).
725 * If 'message' was obtained through some non-thread means, (such as
726 * by a call to notmuch_query_search_messages), then this function
729 * If there are no replies to 'message', this function will return
730 * NULL. (Note that notmuch_messages_valid will accept that NULL
731 * value as legitimate, and simply return FALSE for it.)
733 func (self *Message) GetReplies() *Messages {
734 if self.message == nil {
737 msgs := C.notmuch_message_get_replies(self.message)
741 return &Messages{messages: msgs}
744 /* Get a filename for the email corresponding to 'message'.
746 * The returned filename is an absolute filename, (the initial
747 * component will match notmuch_database_get_path() ).
749 * The returned string belongs to the message so should not be
750 * modified or freed by the caller (nor should it be referenced after
751 * the message is destroyed).
753 * Note: If this message corresponds to multiple files in the mail
754 * store, (that is, multiple files contain identical message IDs),
755 * this function will arbitrarily return a single one of those
758 func (self *Message) GetFileName() string {
759 if self.message == nil {
762 fname := C.notmuch_message_get_filename(self.message)
764 // defer C.free(unsafe.Pointer(fname))
770 return C.GoString(fname)
773 type Flag C.notmuch_message_flag_t
776 MESSAGE_FLAG_MATCH Flag = 0
779 /* Get a value of a flag for the email corresponding to 'message'. */
780 func (self *Message) GetFlag(flag Flag) bool {
781 if self.message == nil {
784 v := C.notmuch_message_get_flag(self.message, C.notmuch_message_flag_t(flag))
791 /* Set a value of a flag for the email corresponding to 'message'. */
792 func (self *Message) SetFlag(flag Flag, value bool) {
793 if self.message == nil {
796 var v C.notmuch_bool_t = 0
800 C.notmuch_message_set_flag(self.message, C.notmuch_message_flag_t(flag), v)
803 // TODO: wrap notmuch_message_get_date
805 /* Get the value of the specified header from 'message'.
807 * The value will be read from the actual message file, not from the
808 * notmuch database. The header name is case insensitive.
810 * The returned string belongs to the message so should not be
811 * modified or freed by the caller (nor should it be referenced after
812 * the message is destroyed).
814 * Returns an empty string ("") if the message does not contain a
815 * header line matching 'header'. Returns NULL if any error occurs.
817 func (self *Message) GetHeader(header string) string {
818 if self.message == nil {
822 var c_header *C.char = C.CString(header)
823 defer C.free(unsafe.Pointer(c_header))
825 /* we dont own value */
826 value := C.notmuch_message_get_header(self.message, c_header)
831 return C.GoString(value)
834 /* Get the tags for 'message', returning a notmuch_tags_t object which
835 * can be used to iterate over all tags.
837 * The tags object is owned by the message and as such, will only be
838 * valid for as long as the message is valid, (which is until the
839 * query from which it derived is destroyed).
841 * Typical usage might be:
843 * notmuch_message_t *message;
844 * notmuch_tags_t *tags;
847 * message = notmuch_database_find_message (database, message_id);
849 * for (tags = notmuch_message_get_tags (message);
850 * notmuch_tags_valid (tags);
851 * notmuch_result_move_to_next (tags))
853 * tag = notmuch_tags_get (tags);
857 * notmuch_message_destroy (message);
859 * Note that there's no explicit destructor needed for the
860 * notmuch_tags_t object. (For consistency, we do provide a
861 * notmuch_tags_destroy function, but there's no good reason to call
862 * it if the message is about to be destroyed).
864 func (self *Message) GetTags() *Tags {
865 if self.message == nil {
868 tags := C.notmuch_message_get_tags(self.message)
872 return &Tags{tags: tags}
875 /* The longest possible tag value. */
878 /* Add a tag to the given message.
882 * NOTMUCH_STATUS_SUCCESS: Tag successfully added to message
884 * NOTMUCH_STATUS_NULL_POINTER: The 'tag' argument is NULL
886 * NOTMUCH_STATUS_TAG_TOO_LONG: The length of 'tag' is too long
887 * (exceeds NOTMUCH_TAG_MAX)
889 * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only
890 * mode so message cannot be modified.
892 func (self *Message) AddTag(tag string) Status {
893 if self.message == nil {
894 return STATUS_NULL_POINTER
896 c_tag := C.CString(tag)
897 defer C.free(unsafe.Pointer(c_tag))
899 return Status(C.notmuch_message_add_tag(self.message, c_tag))
902 /* Remove a tag from the given message.
906 * NOTMUCH_STATUS_SUCCESS: Tag successfully removed from message
908 * NOTMUCH_STATUS_NULL_POINTER: The 'tag' argument is NULL
910 * NOTMUCH_STATUS_TAG_TOO_LONG: The length of 'tag' is too long
911 * (exceeds NOTMUCH_TAG_MAX)
913 * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only
914 * mode so message cannot be modified.
916 func (self *Message) RemoveTag(tag string) Status {
917 if self.message == nil {
918 return STATUS_NULL_POINTER
920 c_tag := C.CString(tag)
921 defer C.free(unsafe.Pointer(c_tag))
923 return Status(C.notmuch_message_remove_tag(self.message, c_tag))
926 /* Remove all tags from the given message.
928 * See notmuch_message_freeze for an example showing how to safely
929 * replace tag values.
931 * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only
932 * mode so message cannot be modified.
934 func (self *Message) RemoveAllTags() Status {
935 if self.message == nil {
936 return STATUS_NULL_POINTER
938 return Status(C.notmuch_message_remove_all_tags(self.message))
941 /* Freeze the current state of 'message' within the database.
943 * This means that changes to the message state, (via
944 * notmuch_message_add_tag, notmuch_message_remove_tag, and
945 * notmuch_message_remove_all_tags), will not be committed to the
946 * database until the message is thawed with notmuch_message_thaw.
948 * Multiple calls to freeze/thaw are valid and these calls will
949 * "stack". That is there must be as many calls to thaw as to freeze
950 * before a message is actually thawed.
952 * The ability to do freeze/thaw allows for safe transactions to
953 * change tag values. For example, explicitly setting a message to
954 * have a given set of tags might look like this:
956 * notmuch_message_freeze (message);
958 * notmuch_message_remove_all_tags (message);
960 * for (i = 0; i < NUM_TAGS; i++)
961 * notmuch_message_add_tag (message, tags[i]);
963 * notmuch_message_thaw (message);
965 * With freeze/thaw used like this, the message in the database is
966 * guaranteed to have either the full set of original tag values, or
967 * the full set of new tag values, but nothing in between.
969 * Imagine the example above without freeze/thaw and the operation
970 * somehow getting interrupted. This could result in the message being
971 * left with no tags if the interruption happened after
972 * notmuch_message_remove_all_tags but before notmuch_message_add_tag.
976 * NOTMUCH_STATUS_SUCCESS: Message successfully frozen.
978 * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only
979 * mode so message cannot be modified.
981 func (self *Message) Freeze() Status {
982 if self.message == nil {
983 return STATUS_NULL_POINTER
985 return Status(C.notmuch_message_freeze(self.message))
988 /* Thaw the current 'message', synchronizing any changes that may have
989 * occurred while 'message' was frozen into the notmuch database.
991 * See notmuch_message_freeze for an example of how to use this
992 * function to safely provide tag changes.
994 * Multiple calls to freeze/thaw are valid and these calls with
995 * "stack". That is there must be as many calls to thaw as to freeze
996 * before a message is actually thawed.
1000 * NOTMUCH_STATUS_SUCCESS: Message successfully thawed, (or at least
1001 * its frozen count has successfully been reduced by 1).
1003 * NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: An attempt was made to thaw
1004 * an unfrozen message. That is, there have been an unbalanced
1005 * number of calls to notmuch_message_freeze and
1006 * notmuch_message_thaw.
1008 func (self *Message) Thaw() Status {
1009 if self.message == nil {
1010 return STATUS_NULL_POINTER
1013 return Status(C.notmuch_message_thaw(self.message))
1016 /* Destroy a notmuch_message_t object.
1018 * It can be useful to call this function in the case of a single
1019 * query object with many messages in the result, (such as iterating
1020 * over the entire database). Otherwise, it's fine to never call this
1021 * function and there will still be no memory leaks. (The memory from
1022 * the messages get reclaimed when the containing query is destroyed.)
1024 func (self *Message) Destroy() {
1025 if self.message == nil {
1028 C.notmuch_message_destroy(self.message)
1031 /* Is the given 'tags' iterator pointing at a valid tag.
1033 * When this function returns TRUE, notmuch_tags_get will return a
1034 * valid string. Whereas when this function returns FALSE,
1035 * notmuch_tags_get will return NULL.
1037 * See the documentation of notmuch_message_get_tags for example code
1038 * showing how to iterate over a notmuch_tags_t object.
1040 func (self *Tags) Valid() bool {
1041 if self.tags == nil {
1044 v := C.notmuch_tags_valid(self.tags)
1051 /* Get the current tag from 'tags' as a string.
1053 * Note: The returned string belongs to 'tags' and has a lifetime
1054 * identical to it (and the query to which it ultimately belongs).
1056 * See the documentation of notmuch_message_get_tags for example code
1057 * showing how to iterate over a notmuch_tags_t object.
1059 func (self *Tags) Get() string {
1060 if self.tags == nil {
1063 s := C.notmuch_tags_get(self.tags)
1066 return C.GoString(s)
1068 func (self *Tags) String() string {
1072 /* Move the 'tags' iterator to the next tag.
1074 * If 'tags' is already pointing at the last tag then the iterator
1075 * will be moved to a point just beyond that last tag, (where
1076 * notmuch_tags_valid will return FALSE and notmuch_tags_get will
1079 * See the documentation of notmuch_message_get_tags for example code
1080 * showing how to iterate over a notmuch_tags_t object.
1082 func (self *Tags) MoveToNext() {
1083 if self.tags == nil {
1086 C.notmuch_tags_move_to_next(self.tags)
1089 /* Destroy a notmuch_tags_t object.
1091 * It's not strictly necessary to call this function. All memory from
1092 * the notmuch_tags_t object will be reclaimed when the containing
1093 * message or query objects are destroyed.
1095 func (self *Tags) Destroy() {
1096 if self.tags == nil {
1099 C.notmuch_tags_destroy(self.tags)
1102 // TODO: wrap notmuch_directory_<fct>
1104 /* Destroy a notmuch_directory_t object. */
1105 func (self *Directory) Destroy() {
1106 if self.dir == nil {
1109 C.notmuch_directory_destroy(self.dir)
1112 // TODO: wrap notmuch_filenames_<fct>
1114 /* Destroy a notmuch_filenames_t object.
1116 * It's not strictly necessary to call this function. All memory from
1117 * the notmuch_filenames_t object will be reclaimed when the
1118 * containing directory object is destroyed.
1120 * It is acceptable to pass NULL for 'filenames', in which case this
1121 * function will do nothing.
1123 func (self *Filenames) Destroy() {
1124 if self.fnames == nil {
1127 C.notmuch_filenames_destroy(self.fnames)