]> git.notmuchmail.org Git - notmuch/blob - bindings/go/src/notmuch/notmuch.go
go: set LDFLAGS to -lnotmuch in the packages source file
[notmuch] / bindings / go / src / notmuch / notmuch.go
1 // Wrapper around the notmuch library
2
3 package notmuch
4
5 /*
6 #cgo LDFLAGS: -lnotmuch
7
8 #include <stdlib.h>
9 #include <string.h>
10 #include <time.h>
11 #include "notmuch.h"
12 */
13 import "C"
14 import "unsafe"
15
16 // Status codes used for the return values of most functions
17 type Status C.notmuch_status_t
18 const (
19         STATUS_SUCCESS Status = iota
20         STATUS_OUT_OF_MEMORY
21     STATUS_READ_ONLY_DATABASE
22     STATUS_XAPIAN_EXCEPTION
23     STATUS_FILE_ERROR
24     STATUS_FILE_NOT_EMAIL
25     STATUS_DUPLICATE_MESSAGE_ID
26     STATUS_NULL_POINTER
27     STATUS_TAG_TOO_LONG
28     STATUS_UNBALANCED_FREEZE_THAW
29     STATUS_UNBALANCED_ATOMIC
30
31     STATUS_LAST_STATUS
32 )
33
34 func (self Status) String() string {
35         var p *C.char
36         
37         // p is read-only
38         p = C.notmuch_status_to_string(C.notmuch_status_t(self))
39         if p != nil {
40                 s := C.GoString(p)
41                 return s
42         }
43         return ""
44 }
45
46 /* Various opaque data types. For each notmuch_<foo>_t see the various
47  * notmuch_<foo> functions below. */
48
49 type Database struct {
50         db *C.notmuch_database_t
51 }
52
53 type Query struct {
54         query *C.notmuch_query_t
55 }
56
57 type Threads struct {
58         threads *C.notmuch_threads_t
59 }
60
61 type Thread struct {
62         thread *C.notmuch_thread_t
63 }
64
65 type Messages struct {
66         messages *C.notmuch_messages_t
67 }
68
69 type Message struct {
70         message *C.notmuch_message_t
71 }
72
73 type Tags struct {
74         tags *C.notmuch_tags_t
75 }
76
77 type Directory struct {
78         dir *C.notmuch_directory_t
79 }
80
81 type Filenames struct {
82         fnames *C.notmuch_filenames_t
83 }
84
85 type DatabaseMode C.notmuch_database_mode_t
86 const (
87     DATABASE_MODE_READ_ONLY DatabaseMode = 0
88     DATABASE_MODE_READ_WRITE
89 )
90
91 // Create a new, empty notmuch database located at 'path'
92 func NewDatabase(path string) (*Database, Status) {
93
94         var c_path *C.char = C.CString(path)
95         defer C.free(unsafe.Pointer(c_path))
96
97         if c_path == nil {
98                 return nil, STATUS_OUT_OF_MEMORY
99         }
100
101         self := &Database{db:nil}
102         st := Status(C.notmuch_database_create(c_path, &self.db))
103         if st != STATUS_SUCCESS {
104                 return nil, st
105         }
106         return self, st
107 }
108
109 /* Open an existing notmuch database located at 'path'.
110  *
111  * The database should have been created at some time in the past,
112  * (not necessarily by this process), by calling
113  * notmuch_database_create with 'path'. By default the database should be
114  * opened for reading only. In order to write to the database you need to
115  * pass the NOTMUCH_DATABASE_MODE_READ_WRITE mode.
116  *
117  * An existing notmuch database can be identified by the presence of a
118  * directory named ".notmuch" below 'path'.
119  *
120  * The caller should call notmuch_database_destroy when finished with
121  * this database.
122  *
123  * In case of any failure, this function returns NULL, (after printing
124  * an error message on stderr).
125  */
126 func OpenDatabase(path string, mode DatabaseMode) (*Database, Status) {
127
128         var c_path *C.char = C.CString(path)
129         defer C.free(unsafe.Pointer(c_path))
130
131         if c_path == nil {
132                 return nil, STATUS_OUT_OF_MEMORY
133         }
134
135         self := &Database{db:nil}
136         st := Status(C.notmuch_database_open(c_path, C.notmuch_database_mode_t(mode), &self.db))
137         if st != STATUS_SUCCESS {
138                 return nil, st
139         }
140         return self, st
141 }
142
143 /* Close the given notmuch database, freeing all associated
144  * resources. See notmuch_database_open. */
145 func (self *Database) Close() {
146         C.notmuch_database_destroy(self.db)
147 }
148
149 /* Return the database path of the given database.
150  */
151 func (self *Database) GetPath() string {
152         
153  /* The return value is a string owned by notmuch so should not be
154   * modified nor freed by the caller. */
155         var p *C.char = C.notmuch_database_get_path(self.db)
156         if p != nil {
157                 s := C.GoString(p)
158                 return s
159         }
160         return ""
161 }
162
163 /* Return the database format version of the given database. */
164 func (self *Database) GetVersion() uint {
165         return uint(C.notmuch_database_get_version(self.db))
166 }
167
168 /* Does this database need to be upgraded before writing to it?
169  *
170  * If this function returns TRUE then no functions that modify the
171  * database (notmuch_database_add_message, notmuch_message_add_tag,
172  * notmuch_directory_set_mtime, etc.) will work unless the function
173  * notmuch_database_upgrade is called successfully first. */
174 func (self *Database) NeedsUpgrade() bool {
175         do_upgrade := C.notmuch_database_needs_upgrade(self.db)
176         if do_upgrade == 0 {
177                 return false
178         }
179         return true
180 }
181
182 // TODO: notmuch_database_upgrade
183
184
185 /* Retrieve a directory object from the database for 'path'.
186  *
187  * Here, 'path' should be a path relative to the path of 'database'
188  * (see notmuch_database_get_path), or else should be an absolute path
189  * with initial components that match the path of 'database'.
190  *
191  * Can return NULL if a Xapian exception occurs.
192  */
193 func (self *Database) GetDirectory(path string) *Directory {
194         var c_path *C.char = C.CString(path)
195         defer C.free(unsafe.Pointer(c_path))
196
197         if c_path == nil {
198                 return nil
199         }
200
201         c_dir := C.notmuch_database_get_directory(self.db, c_path)
202         if c_dir == nil {
203                 return nil
204         }
205         return &Directory{dir:c_dir}
206 }
207
208 /* Add a new message to the given notmuch database.
209  *
210  * Here,'filename' should be a path relative to the path of
211  * 'database' (see notmuch_database_get_path), or else should be an
212  * absolute filename with initial components that match the path of
213  * 'database'.
214  *
215  * The file should be a single mail message (not a multi-message mbox)
216  * that is expected to remain at its current location, (since the
217  * notmuch database will reference the filename, and will not copy the
218  * entire contents of the file.
219  *
220  * If 'message' is not NULL, then, on successful return '*message'
221  * will be initialized to a message object that can be used for things
222  * such as adding tags to the just-added message. The user should call
223  * notmuch_message_destroy when done with the message. On any failure
224  * '*message' will be set to NULL.
225  *
226  * Return value:
227  *
228  * NOTMUCH_STATUS_SUCCESS: Message successfully added to database.
229  *
230  * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred,
231  *      message not added.
232  *
233  * NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: Message has the same message
234  *      ID as another message already in the database. The new
235  *      filename was successfully added to the message in the database
236  *      (if not already present).
237  *
238  * NOTMUCH_STATUS_FILE_ERROR: an error occurred trying to open the
239  *      file, (such as permission denied, or file not found,
240  *      etc.). Nothing added to the database.
241  *
242  * NOTMUCH_STATUS_FILE_NOT_EMAIL: the contents of filename don't look
243  *      like an email message. Nothing added to the database.
244  *
245  * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only
246  *      mode so no message can be added.
247  */
248 func 
249 (self *Database) AddMessage(fname string) (*Message, Status) {
250         var c_fname *C.char = C.CString(fname)
251         defer C.free(unsafe.Pointer(c_fname))
252
253         if c_fname == nil {
254                 return nil, STATUS_OUT_OF_MEMORY
255         }
256
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))
259
260         return &Message{message:c_msg}, st
261 }
262
263 /* Remove a message from the given notmuch database.
264  *
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.
271  *
272  * Return value:
273  *
274  * NOTMUCH_STATUS_SUCCESS: The last filename was removed and the
275  *      message was removed from the database.
276  *
277  * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred,
278  *      message not removed.
279  *
280  * NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: This filename was removed but
281  *      the message persists in the database with at least one other
282  *      filename.
283  *
284  * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only
285  *      mode so no message can be removed.
286  */
287 func (self *Database) RemoveMessage(fname string) Status {
288         
289         var c_fname *C.char = C.CString(fname)
290         defer C.free(unsafe.Pointer(c_fname))
291
292         if c_fname == nil {
293                 return STATUS_OUT_OF_MEMORY
294         }
295
296         st := C.notmuch_database_remove_message(self.db, c_fname)
297         return Status(st)
298 }
299
300 /* Find a message with the given message_id.
301  *
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.
305  *
306  * This function returns NULL in the following situations:
307  *
308  *      * No message is found with the given message_id
309  *      * An out-of-memory situation occurs
310  *      * A Xapian exception occurs
311  */
312 func (self *Database) FindMessage(message_id string) (*Message, Status) {
313         
314         var c_msg_id *C.char = C.CString(message_id)
315         defer C.free(unsafe.Pointer(c_msg_id))
316
317         if c_msg_id == nil {
318                 return nil, STATUS_OUT_OF_MEMORY
319         }
320
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 {
324                 return nil, st
325         }
326         return msg, st
327 }
328
329 /* Return a list of all tags found in the database.
330  *
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.
333  *
334  * On error this function returns NULL.
335  */
336 func (self *Database) GetAllTags() *Tags {
337         tags := C.notmuch_database_get_all_tags(self.db)
338         if tags == nil {
339                 return nil
340         }
341         return &Tags{tags:tags}
342 }
343
344 /* Create a new query for 'database'.
345  *
346  * Here, 'database' should be an open database, (see
347  * notmuch_database_open and notmuch_database_create).
348  *
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:
352  *
353  * http://xapian.org/docs/queryparser.html
354  *
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.
358  *
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.
362  *
363  * User should call notmuch_query_destroy when finished with this
364  * query.
365  *
366  * Will return NULL if insufficient memory is available.
367  */
368 func (self *Database) CreateQuery(query string) *Query {
369         
370         var c_query *C.char = C.CString(query)
371         defer C.free(unsafe.Pointer(c_query))
372
373         if c_query == nil {
374                 return nil
375         }
376
377         q := C.notmuch_query_create(self.db, c_query)
378         if q == nil {
379                 return nil
380         }
381         return &Query{query:q}
382 }
383
384 /* Sort values for notmuch_query_set_sort */
385 type Sort C.notmuch_sort_t
386 const (
387         SORT_OLDEST_FIRST Sort = 0
388         SORT_NEWEST_FIRST
389         SORT_MESSAGE_ID
390         SORT_UNSORTED
391 )
392
393 /* Return the query_string of this query. See notmuch_query_create. */
394 func (self *Query) String() string {
395         // FIXME: do we own 'q' or not ?
396         q := C.notmuch_query_get_query_string(self.query)
397         //defer C.free(unsafe.Pointer(q))
398         
399         if q != nil {
400                 s := C.GoString(q)
401                 return s
402         }
403
404         return ""
405 }
406
407 /* Specify the sorting desired for this query. */
408 func (self *Query) SetSort(sort Sort) {
409         C.notmuch_query_set_sort(self.query, C.notmuch_sort_t(sort))
410 }
411
412 /* Return the sort specified for this query. See notmuch_query_set_sort. */
413 func (self *Query) GetSort() Sort {
414         return Sort(C.notmuch_query_get_sort(self.query))
415 }
416
417 /* Execute a query for threads, returning a notmuch_threads_t object
418  * which can be used to iterate over the results. The returned threads
419  * object is owned by the query and as such, will only be valid until
420  * notmuch_query_destroy.
421  *
422  * Typical usage might be:
423  *
424  *     notmuch_query_t *query;
425  *     notmuch_threads_t *threads;
426  *     notmuch_thread_t *thread;
427  *
428  *     query = notmuch_query_create (database, query_string);
429  *
430  *     for (threads = notmuch_query_search_threads (query);
431  *          notmuch_threads_valid (threads);
432  *          notmuch_threads_move_to_next (threads))
433  *     {
434  *         thread = notmuch_threads_get (threads);
435  *         ....
436  *         notmuch_thread_destroy (thread);
437  *     }
438  *
439  *     notmuch_query_destroy (query);
440  *
441  * Note: If you are finished with a thread before its containing
442  * query, you can call notmuch_thread_destroy to clean up some memory
443  * sooner (as in the above example). Otherwise, if your thread objects
444  * are long-lived, then you don't need to call notmuch_thread_destroy
445  * and all the memory will still be reclaimed when the query is
446  * destroyed.
447  *
448  * Note that there's no explicit destructor needed for the
449  * notmuch_threads_t object. (For consistency, we do provide a
450  * notmuch_threads_destroy function, but there's no good reason
451  * to call it if the query is about to be destroyed).
452  *
453  * If a Xapian exception occurs this function will return NULL.
454  */
455 func (self *Query) SearchThreads() *Threads {
456         threads := C.notmuch_query_search_threads(self.query)
457         if threads == nil {
458                 return nil
459         }
460         return &Threads{threads:threads}
461 }
462
463 /* Execute a query for messages, returning a notmuch_messages_t object
464  * which can be used to iterate over the results. The returned
465  * messages object is owned by the query and as such, will only be
466  * valid until notmuch_query_destroy.
467  *
468  * Typical usage might be:
469  *
470  *     notmuch_query_t *query;
471  *     notmuch_messages_t *messages;
472  *     notmuch_message_t *message;
473  *
474  *     query = notmuch_query_create (database, query_string);
475  *
476  *     for (messages = notmuch_query_search_messages (query);
477  *          notmuch_messages_valid (messages);
478  *          notmuch_messages_move_to_next (messages))
479  *     {
480  *         message = notmuch_messages_get (messages);
481  *         ....
482  *         notmuch_message_destroy (message);
483  *     }
484  *
485  *     notmuch_query_destroy (query);
486  *
487  * Note: If you are finished with a message before its containing
488  * query, you can call notmuch_message_destroy to clean up some memory
489  * sooner (as in the above example). Otherwise, if your message
490  * objects are long-lived, then you don't need to call
491  * notmuch_message_destroy and all the memory will still be reclaimed
492  * when the query is destroyed.
493  *
494  * Note that there's no explicit destructor needed for the
495  * notmuch_messages_t object. (For consistency, we do provide a
496  * notmuch_messages_destroy function, but there's no good
497  * reason to call it if the query is about to be destroyed).
498  *
499  * If a Xapian exception occurs this function will return NULL.
500  */
501 func (self *Query) SearchMessages() *Messages {
502         msgs := C.notmuch_query_search_messages(self.query)
503         if msgs == nil {
504                 return nil
505         }
506         return &Messages{messages:msgs}
507 }
508
509 /* Destroy a notmuch_query_t along with any associated resources.
510  *
511  * This will in turn destroy any notmuch_threads_t and
512  * notmuch_messages_t objects generated by this query, (and in
513  * turn any notmuch_thread_t and notmuch_message_t objects generated
514  * from those results, etc.), if such objects haven't already been
515  * destroyed.
516  */
517 func (self *Query) Destroy() {
518         if self.query != nil {
519                 C.notmuch_query_destroy(self.query)
520         }
521 }
522
523 /* Return an estimate of the number of messages matching a search
524  *
525  * This function performs a search and returns Xapian's best
526  * guess as to number of matching messages.
527  *
528  * If a Xapian exception occurs, this function may return 0 (after
529  * printing a message).
530  */
531 func (self *Query) CountMessages() uint {
532         return uint(C.notmuch_query_count_messages(self.query))
533 }
534
535 // TODO: wrap threads and thread
536
537 /* Is the given 'threads' iterator pointing at a valid thread.
538  *
539  * When this function returns TRUE, notmuch_threads_get will return a
540  * valid object. Whereas when this function returns FALSE,
541  * notmuch_threads_get will return NULL.
542  *
543  * See the documentation of notmuch_query_search_threads for example
544  * code showing how to iterate over a notmuch_threads_t object.
545  */
546 func (self *Threads) Valid() bool {
547         if self.threads == nil {
548                 return false
549         }
550         valid := C.notmuch_threads_valid(self.threads)
551         if valid == 0 {
552                 return false
553         }
554         return true
555 }
556
557 /* Destroy a notmuch_threads_t object.
558  *
559  * It's not strictly necessary to call this function. All memory from
560  * the notmuch_threads_t object will be reclaimed when the
561  * containg query object is destroyed.
562  */
563 func (self *Threads) Destroy() {
564         if self.threads != nil {
565                 C.notmuch_threads_destroy(self.threads)
566         }
567 }
568
569 /* Is the given 'messages' iterator pointing at a valid message.
570  *
571  * When this function returns TRUE, notmuch_messages_get will return a
572  * valid object. Whereas when this function returns FALSE,
573  * notmuch_messages_get will return NULL.
574  *
575  * See the documentation of notmuch_query_search_messages for example
576  * code showing how to iterate over a notmuch_messages_t object.
577  */
578 func (self *Messages) Valid() bool {
579         if self.messages == nil {
580                 return false
581         }
582         valid := C.notmuch_messages_valid(self.messages)
583         if valid == 0 {
584                 return false
585         }
586         return true
587 }
588
589 /* Get the current message from 'messages' as a notmuch_message_t.
590  *
591  * Note: The returned message belongs to 'messages' and has a lifetime
592  * identical to it (and the query to which it belongs).
593  *
594  * See the documentation of notmuch_query_search_messages for example
595  * code showing how to iterate over a notmuch_messages_t object.
596  *
597  * If an out-of-memory situation occurs, this function will return
598  * NULL.
599  */
600 func (self *Messages) Get() *Message {
601         if self.messages == nil {
602                 return nil
603         }
604         msg := C.notmuch_messages_get(self.messages)
605         if msg == nil {
606                 return nil
607         }
608         return &Message{message:msg}
609 }
610
611 /* Move the 'messages' iterator to the next message.
612  *
613  * If 'messages' is already pointing at the last message then the
614  * iterator will be moved to a point just beyond that last message,
615  * (where notmuch_messages_valid will return FALSE and
616  * notmuch_messages_get will return NULL).
617  *
618  * See the documentation of notmuch_query_search_messages for example
619  * code showing how to iterate over a notmuch_messages_t object.
620  */
621 func (self *Messages) MoveToNext() {
622         if self.messages == nil {
623                 return
624         }
625         C.notmuch_messages_move_to_next(self.messages)
626 }
627
628 /* Destroy a notmuch_messages_t object.
629  *
630  * It's not strictly necessary to call this function. All memory from
631  * the notmuch_messages_t object will be reclaimed when the containing
632  * query object is destroyed.
633  */
634 func (self *Messages) Destroy() {
635         if self.messages != nil {
636                 C.notmuch_messages_destroy(self.messages)
637         }
638 }
639
640 /* Return a list of tags from all messages.
641  *
642  * The resulting list is guaranteed not to contain duplicated tags.
643  *
644  * WARNING: You can no longer iterate over messages after calling this
645  * function, because the iterator will point at the end of the list.
646  * We do not have a function to reset the iterator yet and the only
647  * way how you can iterate over the list again is to recreate the
648  * message list.
649  *
650  * The function returns NULL on error.
651  */
652 func (self *Messages) CollectTags() *Tags {
653         if self.messages == nil {
654                 return nil
655         }
656         tags := C.notmuch_messages_collect_tags(self.messages)
657         if tags == nil {
658                 return nil
659         }
660         return &Tags{tags:tags}
661 }
662
663 /* Get the message ID of 'message'.
664  *
665  * The returned string belongs to 'message' and as such, should not be
666  * modified by the caller and will only be valid for as long as the
667  * message is valid, (which is until the query from which it derived
668  * is destroyed).
669  *
670  * This function will not return NULL since Notmuch ensures that every
671  * message has a unique message ID, (Notmuch will generate an ID for a
672  * message if the original file does not contain one).
673  */
674 func (self *Message) GetMessageId() string {
675
676         if self.message == nil {
677                 return ""
678         }
679         id := C.notmuch_message_get_message_id(self.message)
680         // we dont own id
681         // defer C.free(unsafe.Pointer(id))
682         if id == nil {
683                 return ""
684         }
685         return C.GoString(id)
686 }
687
688 /* Get the thread ID of 'message'.
689  *
690  * The returned string belongs to 'message' and as such, should not be
691  * modified by the caller and will only be valid for as long as the
692  * message is valid, (for example, until the user calls
693  * notmuch_message_destroy on 'message' or until a query from which it
694  * derived is destroyed).
695  *
696  * This function will not return NULL since Notmuch ensures that every
697  * message belongs to a single thread.
698  */
699 func (self *Message) GetThreadId() string {
700         
701         if self.message == nil {
702                 return ""
703         }
704         id := C.notmuch_message_get_thread_id(self.message)
705         // we dont own id
706         // defer C.free(unsafe.Pointer(id))
707         
708         if id == nil {
709                 return ""
710         }
711
712         return C.GoString(id)
713 }
714
715 /* Get a notmuch_messages_t iterator for all of the replies to
716  * 'message'.
717  *
718  * Note: This call only makes sense if 'message' was ultimately
719  * obtained from a notmuch_thread_t object, (such as by coming
720  * directly from the result of calling notmuch_thread_get_
721  * toplevel_messages or by any number of subsequent
722  * calls to notmuch_message_get_replies).
723  *
724  * If 'message' was obtained through some non-thread means, (such as
725  * by a call to notmuch_query_search_messages), then this function
726  * will return NULL.
727  *
728  * If there are no replies to 'message', this function will return
729  * NULL. (Note that notmuch_messages_valid will accept that NULL
730  * value as legitimate, and simply return FALSE for it.)
731  */
732 func (self *Message) GetReplies() *Messages {
733         if self.message == nil {
734                 return nil
735         }
736         msgs := C.notmuch_message_get_replies(self.message)
737         if msgs == nil {
738                 return nil
739         }
740         return &Messages{messages:msgs}
741 }
742
743 /* Get a filename for the email corresponding to 'message'.
744  *
745  * The returned filename is an absolute filename, (the initial
746  * component will match notmuch_database_get_path() ).
747  *
748  * The returned string belongs to the message so should not be
749  * modified or freed by the caller (nor should it be referenced after
750  * the message is destroyed).
751  *
752  * Note: If this message corresponds to multiple files in the mail
753  * store, (that is, multiple files contain identical message IDs),
754  * this function will arbitrarily return a single one of those
755  * filenames.
756  */
757 func (self *Message) GetFileName() string {
758         if self.message == nil {
759                 return ""
760         }
761         fname := C.notmuch_message_get_filename(self.message)
762         // we dont own fname
763         // defer C.free(unsafe.Pointer(fname))
764         
765         if fname == nil {
766                 return ""
767         }
768
769         return C.GoString(fname)
770 }
771
772 type Flag C.notmuch_message_flag_t
773 const (
774         MESSAGE_FLAG_MATCH Flag = 0
775 )
776
777 /* Get a value of a flag for the email corresponding to 'message'. */
778 func (self *Message) GetFlag(flag Flag) bool {
779         if self.message == nil {
780                 return false
781         }
782         v := C.notmuch_message_get_flag(self.message, C.notmuch_message_flag_t(flag))
783         if v == 0 {
784                 return false
785         }
786         return true
787 }
788
789 /* Set a value of a flag for the email corresponding to 'message'. */
790 func (self *Message) SetFlag(flag Flag, value bool) {
791         if self.message == nil {
792                 return
793         }
794         var v C.notmuch_bool_t = 0
795         if value {
796                 v = 1
797         }
798         C.notmuch_message_set_flag(self.message, C.notmuch_message_flag_t(flag), v)
799 }
800
801 // TODO: wrap notmuch_message_get_date
802
803 /* Get the value of the specified header from 'message'.
804  *
805  * The value will be read from the actual message file, not from the
806  * notmuch database. The header name is case insensitive.
807  *
808  * The returned string belongs to the message so should not be
809  * modified or freed by the caller (nor should it be referenced after
810  * the message is destroyed).
811  *
812  * Returns an empty string ("") if the message does not contain a
813  * header line matching 'header'. Returns NULL if any error occurs.
814  */
815 func (self *Message) GetHeader(header string) string {
816         if self.message == nil {
817                 return ""
818         }
819         
820         var c_header *C.char = C.CString(header)
821         defer C.free(unsafe.Pointer(c_header))
822         
823         /* we dont own value */
824         value := C.notmuch_message_get_header(self.message, c_header)
825         if value == nil {
826                 return ""
827         }
828         
829         return C.GoString(value)
830 }
831
832 /* Get the tags for 'message', returning a notmuch_tags_t object which
833  * can be used to iterate over all tags.
834  *
835  * The tags object is owned by the message and as such, will only be
836  * valid for as long as the message is valid, (which is until the
837  * query from which it derived is destroyed).
838  *
839  * Typical usage might be:
840  *
841  *     notmuch_message_t *message;
842  *     notmuch_tags_t *tags;
843  *     const char *tag;
844  *
845  *     message = notmuch_database_find_message (database, message_id);
846  *
847  *     for (tags = notmuch_message_get_tags (message);
848  *          notmuch_tags_valid (tags);
849  *          notmuch_result_move_to_next (tags))
850  *     {
851  *         tag = notmuch_tags_get (tags);
852  *         ....
853  *     }
854  *
855  *     notmuch_message_destroy (message);
856  *
857  * Note that there's no explicit destructor needed for the
858  * notmuch_tags_t object. (For consistency, we do provide a
859  * notmuch_tags_destroy function, but there's no good reason to call
860  * it if the message is about to be destroyed).
861  */
862 func (self *Message) GetTags() *Tags {
863         if self.message == nil {
864                 return nil
865         }
866         tags := C.notmuch_message_get_tags(self.message)
867         if tags == nil {
868                 return nil
869         }
870         return &Tags{tags:tags}
871 }
872
873 /* The longest possible tag value. */
874 const TAG_MAX = 200
875
876 /* Add a tag to the given message.
877  *
878  * Return value:
879  *
880  * NOTMUCH_STATUS_SUCCESS: Tag successfully added to message
881  *
882  * NOTMUCH_STATUS_NULL_POINTER: The 'tag' argument is NULL
883  *
884  * NOTMUCH_STATUS_TAG_TOO_LONG: The length of 'tag' is too long
885  *      (exceeds NOTMUCH_TAG_MAX)
886  *
887  * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only
888  *      mode so message cannot be modified.
889  */
890 func (self *Message) AddTag(tag string) Status {
891         if self.message == nil {
892                 return STATUS_NULL_POINTER
893         }
894         c_tag := C.CString(tag)
895         defer C.free(unsafe.Pointer(c_tag))
896
897         return Status(C.notmuch_message_add_tag(self.message, c_tag))
898 }
899
900 /* Remove a tag from the given message.
901  *
902  * Return value:
903  *
904  * NOTMUCH_STATUS_SUCCESS: Tag successfully removed from message
905  *
906  * NOTMUCH_STATUS_NULL_POINTER: The 'tag' argument is NULL
907  *
908  * NOTMUCH_STATUS_TAG_TOO_LONG: The length of 'tag' is too long
909  *      (exceeds NOTMUCH_TAG_MAX)
910  *
911  * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only
912  *      mode so message cannot be modified.
913  */
914 func (self *Message) RemoveTag(tag string) Status {
915         if self.message == nil {
916                 return STATUS_NULL_POINTER
917         }
918         c_tag := C.CString(tag)
919         defer C.free(unsafe.Pointer(c_tag))
920
921         return Status(C.notmuch_message_remove_tag(self.message, c_tag))
922 }
923
924 /* Remove all tags from the given message.
925  *
926  * See notmuch_message_freeze for an example showing how to safely
927  * replace tag values.
928  *
929  * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only
930  *      mode so message cannot be modified.
931  */
932 func (self *Message) RemoveAllTags() Status {
933         if self.message == nil {
934                 return STATUS_NULL_POINTER
935         }
936         return Status(C.notmuch_message_remove_all_tags(self.message))
937 }
938
939 /* Freeze the current state of 'message' within the database.
940  *
941  * This means that changes to the message state, (via
942  * notmuch_message_add_tag, notmuch_message_remove_tag, and
943  * notmuch_message_remove_all_tags), will not be committed to the
944  * database until the message is thawed with notmuch_message_thaw.
945  *
946  * Multiple calls to freeze/thaw are valid and these calls will
947  * "stack". That is there must be as many calls to thaw as to freeze
948  * before a message is actually thawed.
949  *
950  * The ability to do freeze/thaw allows for safe transactions to
951  * change tag values. For example, explicitly setting a message to
952  * have a given set of tags might look like this:
953  *
954  *    notmuch_message_freeze (message);
955  *
956  *    notmuch_message_remove_all_tags (message);
957  *
958  *    for (i = 0; i < NUM_TAGS; i++)
959  *        notmuch_message_add_tag (message, tags[i]);
960  *
961  *    notmuch_message_thaw (message);
962  *
963  * With freeze/thaw used like this, the message in the database is
964  * guaranteed to have either the full set of original tag values, or
965  * the full set of new tag values, but nothing in between.
966  *
967  * Imagine the example above without freeze/thaw and the operation
968  * somehow getting interrupted. This could result in the message being
969  * left with no tags if the interruption happened after
970  * notmuch_message_remove_all_tags but before notmuch_message_add_tag.
971  *
972  * Return value:
973  *
974  * NOTMUCH_STATUS_SUCCESS: Message successfully frozen.
975  *
976  * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only
977  *      mode so message cannot be modified.
978  */
979 func (self *Message) Freeze() Status {
980         if self.message == nil {
981                 return STATUS_NULL_POINTER
982         }
983         return Status(C.notmuch_message_freeze(self.message))
984 }
985
986 /* Thaw the current 'message', synchronizing any changes that may have
987  * occurred while 'message' was frozen into the notmuch database.
988  *
989  * See notmuch_message_freeze for an example of how to use this
990  * function to safely provide tag changes.
991  *
992  * Multiple calls to freeze/thaw are valid and these calls with
993  * "stack". That is there must be as many calls to thaw as to freeze
994  * before a message is actually thawed.
995  *
996  * Return value:
997  *
998  * NOTMUCH_STATUS_SUCCESS: Message successfully thawed, (or at least
999  *      its frozen count has successfully been reduced by 1).
1000  *
1001  * NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: An attempt was made to thaw
1002  *      an unfrozen message. That is, there have been an unbalanced
1003  *      number of calls to notmuch_message_freeze and
1004  *      notmuch_message_thaw.
1005  */
1006 func (self *Message) Thaw() Status {
1007         if self.message == nil {
1008                 return STATUS_NULL_POINTER
1009         }
1010
1011         return Status(C.notmuch_message_thaw(self.message))
1012 }
1013
1014 /* Destroy a notmuch_message_t object.
1015  *
1016  * It can be useful to call this function in the case of a single
1017  * query object with many messages in the result, (such as iterating
1018  * over the entire database). Otherwise, it's fine to never call this
1019  * function and there will still be no memory leaks. (The memory from
1020  * the messages get reclaimed when the containing query is destroyed.)
1021  */
1022 func (self *Message) Destroy() {
1023         if self.message == nil {
1024                 return
1025         }
1026         C.notmuch_message_destroy(self.message)
1027 }
1028
1029 /* Is the given 'tags' iterator pointing at a valid tag.
1030  *
1031  * When this function returns TRUE, notmuch_tags_get will return a
1032  * valid string. Whereas when this function returns FALSE,
1033  * notmuch_tags_get will return NULL.
1034  *
1035  * See the documentation of notmuch_message_get_tags for example code
1036  * showing how to iterate over a notmuch_tags_t object.
1037  */
1038 func (self *Tags) Valid() bool {
1039         if self.tags == nil {
1040                 return false
1041         }
1042         v := C.notmuch_tags_valid(self.tags)
1043         if v == 0 {
1044                 return false
1045         }
1046         return true
1047 }
1048
1049 /* Get the current tag from 'tags' as a string.
1050  *
1051  * Note: The returned string belongs to 'tags' and has a lifetime
1052  * identical to it (and the query to which it ultimately belongs).
1053  *
1054  * See the documentation of notmuch_message_get_tags for example code
1055  * showing how to iterate over a notmuch_tags_t object.
1056  */
1057 func (self *Tags) Get() string {
1058         if self.tags == nil {
1059                 return ""
1060         }
1061         s := C.notmuch_tags_get(self.tags)
1062         // we dont own 's'
1063
1064         return C.GoString(s)
1065 }
1066 func (self *Tags) String() string {
1067         return self.Get()
1068 }
1069
1070 /* Move the 'tags' iterator to the next tag.
1071  *
1072  * If 'tags' is already pointing at the last tag then the iterator
1073  * will be moved to a point just beyond that last tag, (where
1074  * notmuch_tags_valid will return FALSE and notmuch_tags_get will
1075  * return NULL).
1076  *
1077  * See the documentation of notmuch_message_get_tags for example code
1078  * showing how to iterate over a notmuch_tags_t object.
1079  */
1080 func (self *Tags) MoveToNext() {
1081         if self.tags == nil {
1082                 return
1083         }
1084         C.notmuch_tags_move_to_next(self.tags)
1085 }
1086
1087 /* Destroy a notmuch_tags_t object.
1088  *
1089  * It's not strictly necessary to call this function. All memory from
1090  * the notmuch_tags_t object will be reclaimed when the containing
1091  * message or query objects are destroyed.
1092  */
1093 func (self *Tags) Destroy() {
1094         if self.tags == nil {
1095                 return
1096         }
1097         C.notmuch_tags_destroy(self.tags)
1098 }
1099
1100 // TODO: wrap notmuch_directory_<fct>
1101
1102 /* Destroy a notmuch_directory_t object. */
1103 func (self *Directory) Destroy() {
1104         if self.dir == nil {
1105                 return
1106         }
1107         C.notmuch_directory_destroy(self.dir)
1108 }
1109
1110 // TODO: wrap notmuch_filenames_<fct>
1111
1112 /* Destroy a notmuch_filenames_t object.
1113  *
1114  * It's not strictly necessary to call this function. All memory from
1115  * the notmuch_filenames_t object will be reclaimed when the
1116  * containing directory object is destroyed.
1117  *
1118  * It is acceptable to pass NULL for 'filenames', in which case this
1119  * function will do nothing.
1120  */
1121 func (self *Filenames) Destroy() {
1122         if self.fnames == nil {
1123                 return
1124         }
1125         C.notmuch_filenames_destroy(self.fnames)
1126 }
1127 /* EOF */