init: pristine aerc 0.20.0 source
This commit is contained in:
@@ -0,0 +1,314 @@
|
||||
//go:build notmuch
|
||||
// +build notmuch
|
||||
|
||||
package notmuch
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lnotmuch
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <notmuch.h>
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type Mode int
|
||||
|
||||
const (
|
||||
MODE_READ_ONLY Mode = C.NOTMUCH_DATABASE_MODE_READ_ONLY
|
||||
MODE_READ_WRITE Mode = C.NOTMUCH_DATABASE_MODE_READ_WRITE
|
||||
)
|
||||
|
||||
type Database struct {
|
||||
// The path to the notmuch database. If Path is the empty string, the
|
||||
// location will be found in the following order:
|
||||
//
|
||||
// 1. The value of the environment variable NOTMUCH_DATABASE
|
||||
// 2. From the config file specified by Config
|
||||
// 3. From the Profile specified by profile, given by
|
||||
// $XDG_DATA_HOME/notmuch/$PROFILE
|
||||
Path string
|
||||
|
||||
// The path to the notmuch configuration file to use.
|
||||
Config string
|
||||
|
||||
// If FindConfig is true, libnotmuch will attempt to locate a suitable
|
||||
// configuration file in the following order:
|
||||
//
|
||||
// 1. The value of the environment variable NOTMUCH_CONFIG
|
||||
// 2. $XDG_CONFIG_HOME/notmuch/
|
||||
// 3. $HOME/.notmuch-config
|
||||
//
|
||||
// If not configuration file is found, a STATUS_NO_CONFIG error will be
|
||||
// returned
|
||||
FindConfig bool
|
||||
|
||||
// The profile to use. If Profile is non-empty, the value will be
|
||||
// appended to the paths determined for Config and Path. If Profile is
|
||||
// the empty string, the profile will be determined in the following
|
||||
// order:
|
||||
//
|
||||
// 1. The value of the environment variable NOTMUCH_PROFILE
|
||||
// 2. "default" if Config and/or Path are a directory, "" if they are a
|
||||
// filepath
|
||||
Profile string
|
||||
|
||||
db *C.notmuch_database_t
|
||||
open bool
|
||||
}
|
||||
|
||||
// Create creates a notmuch database at the Path
|
||||
func (db *Database) Create() error {
|
||||
var cdb *C.notmuch_database_t
|
||||
var cPath *C.char
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
if db.Path != "" {
|
||||
cPath = C.CString(db.Path)
|
||||
}
|
||||
err := errorWrap(C.notmuch_database_create(cPath, &cdb)) //nolint:gocritic // see note in notmuch.go
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
db.db = cdb
|
||||
return nil
|
||||
}
|
||||
|
||||
// Open opens the database with the given mode. Caller must call Close when done
|
||||
// to commit changes and free resources
|
||||
func (db *Database) Open(mode Mode) error {
|
||||
var (
|
||||
cPath *C.char
|
||||
cConfig *C.char
|
||||
cProfile *C.char
|
||||
cErr *C.char
|
||||
)
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
defer C.free(unsafe.Pointer(cConfig))
|
||||
defer C.free(unsafe.Pointer(cProfile))
|
||||
defer C.free(unsafe.Pointer(cErr))
|
||||
|
||||
if db.Path != "" {
|
||||
cPath = C.CString(db.Path)
|
||||
}
|
||||
|
||||
if !db.FindConfig {
|
||||
cConfig = C.CString(db.Config)
|
||||
}
|
||||
|
||||
if db.Profile != "" {
|
||||
cProfile = C.CString(db.Profile)
|
||||
}
|
||||
cmode := C.notmuch_database_mode_t(mode)
|
||||
|
||||
var cdb *C.notmuch_database_t
|
||||
|
||||
// gocritic:dupSubExpr throws an issue here no matter how we call this
|
||||
// function
|
||||
err := errorWrap(
|
||||
C.notmuch_database_open_with_config(
|
||||
cPath, cmode, cConfig, cProfile, &cdb, &cErr, //nolint:gocritic // see above
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
db.db = cdb
|
||||
db.open = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reopen an open notmuch database, usually with a different mode
|
||||
func (db *Database) Reopen(mode Mode) error {
|
||||
cmode := C.notmuch_database_mode_t(mode)
|
||||
return errorWrap(C.notmuch_database_reopen(db.db, cmode))
|
||||
}
|
||||
|
||||
// Close commits changes and closes the database, freeing any resources
|
||||
// associated with it
|
||||
func (db *Database) Close() error {
|
||||
if !db.open {
|
||||
return nil
|
||||
}
|
||||
err := errorWrap(C.notmuch_database_close(db.db))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = errorWrap(C.notmuch_database_destroy(db.db))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
db.open = false
|
||||
return nil
|
||||
}
|
||||
|
||||
// LastStatus returns the last status string for the database
|
||||
func (db *Database) LastStatus() string {
|
||||
cStatus := C.notmuch_database_status_string(db.db)
|
||||
defer C.free(unsafe.Pointer(cStatus))
|
||||
return C.GoString(cStatus)
|
||||
}
|
||||
|
||||
func (db *Database) Compact(backupPath string) error {
|
||||
if backupPath == "" {
|
||||
return fmt.Errorf("must have backup path before compacting")
|
||||
}
|
||||
var cBackupPath *C.char
|
||||
defer C.free(unsafe.Pointer(cBackupPath))
|
||||
return errorWrap(C.notmuch_database_compact_db(db.db, cBackupPath, nil, nil))
|
||||
}
|
||||
|
||||
// Return the resolved path to the notmuch database
|
||||
func (db *Database) ResolvedPath() string {
|
||||
cPath := C.notmuch_database_get_path(db.db)
|
||||
return C.GoString(cPath)
|
||||
}
|
||||
|
||||
// NeedsUpgrade reports if the database must be upgraded before a write
|
||||
// operation can be safely performed
|
||||
func (db *Database) NeedsUpgrade() bool {
|
||||
return C.notmuch_database_needs_upgrade(db.db) == 1
|
||||
}
|
||||
|
||||
// Indicate the beginning of an atomic operation
|
||||
func (db *Database) BeginAtomic() error {
|
||||
return errorWrap(C.notmuch_database_begin_atomic(db.db))
|
||||
}
|
||||
|
||||
// Indicate the end of an atomic operation
|
||||
func (db *Database) EndAtomic() error {
|
||||
return errorWrap(C.notmuch_database_end_atomic(db.db))
|
||||
}
|
||||
|
||||
// Returns the UUID and LastMod of the notmuch database
|
||||
func (db *Database) Revision() (string, uint64) {
|
||||
var uuid *C.char
|
||||
defer C.free(unsafe.Pointer(uuid))
|
||||
lastmod := uint64(C.notmuch_database_get_revision(db.db, &uuid)) //nolint:gocritic // see note in notmuch.go
|
||||
return C.GoString(uuid), lastmod
|
||||
}
|
||||
|
||||
// Returns a Directory object relative to the path of the Database
|
||||
func (db *Database) Directory(relativePath string) (Directory, error) {
|
||||
var result Directory
|
||||
|
||||
if relativePath == "" {
|
||||
return result, fmt.Errorf("path can't be empty")
|
||||
}
|
||||
var (
|
||||
dir *C.notmuch_directory_t
|
||||
cPath *C.char
|
||||
)
|
||||
cPath = C.CString(relativePath)
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
err := errorWrap(C.notmuch_database_get_directory(db.db, cPath, &dir)) //nolint:gocritic // see note in notmuch.go
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
result.dir = dir
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// IndexFile indexes a file with path relative to the database path, or an
|
||||
// absolute path which share a common ancestor as the database path
|
||||
func (db *Database) IndexFile(path string) (Message, error) {
|
||||
var (
|
||||
cPath *C.char
|
||||
msg *C.notmuch_message_t
|
||||
)
|
||||
cPath = C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
|
||||
err := errorWrap(C.notmuch_database_index_file(db.db, cPath, nil, &msg)) //nolint:gocritic // see note in notmuch.go
|
||||
switch {
|
||||
case errors.Is(err, STATUS_DUPLICATE_MESSAGE_ID):
|
||||
break
|
||||
case err != nil:
|
||||
return Message{}, err
|
||||
}
|
||||
message := Message{
|
||||
message: msg,
|
||||
}
|
||||
return message, nil
|
||||
}
|
||||
|
||||
// Remove a file from the database. If this is the last file associated with a
|
||||
// message, the message will be removed from the database.
|
||||
func (db *Database) RemoveFile(path string) error {
|
||||
cPath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
return errorWrap(C.notmuch_database_remove_message(db.db, cPath))
|
||||
}
|
||||
|
||||
// FindMessageByID finds a message by the Message-ID header field value
|
||||
func (db *Database) FindMessageByID(id string) (Message, error) {
|
||||
var (
|
||||
cID *C.char
|
||||
msg *C.notmuch_message_t
|
||||
)
|
||||
cID = C.CString(id)
|
||||
defer C.free(unsafe.Pointer(cID))
|
||||
err := errorWrap(C.notmuch_database_find_message(db.db, cID, &msg)) //nolint:gocritic // see note in notmuch.go
|
||||
if err != nil {
|
||||
return Message{}, err
|
||||
}
|
||||
message := Message{
|
||||
message: msg,
|
||||
}
|
||||
return message, nil
|
||||
}
|
||||
|
||||
// FindMessageByFilename finds a message by filename
|
||||
func (db *Database) FindMessageByFilename(filename string) (Message, error) {
|
||||
var (
|
||||
cFilename *C.char
|
||||
msg *C.notmuch_message_t
|
||||
)
|
||||
cFilename = C.CString(filename)
|
||||
defer C.free(unsafe.Pointer(cFilename))
|
||||
err := errorWrap(C.notmuch_database_find_message_by_filename(db.db, cFilename, &msg)) //nolint:gocritic // see note in notmuch.go
|
||||
if err != nil {
|
||||
return Message{}, err
|
||||
}
|
||||
if msg == nil {
|
||||
return Message{}, fmt.Errorf("couldn't find message by filename: %s", filename)
|
||||
}
|
||||
message := Message{
|
||||
message: msg,
|
||||
}
|
||||
return message, nil
|
||||
}
|
||||
|
||||
// Tags returns a slice of all tags in the database
|
||||
func (db *Database) Tags() []string {
|
||||
cTags := C.notmuch_database_get_all_tags(db.db)
|
||||
defer C.notmuch_tags_destroy(cTags)
|
||||
|
||||
tags := []string{}
|
||||
for C.notmuch_tags_valid(cTags) > 0 {
|
||||
tag := C.notmuch_tags_get(cTags)
|
||||
tags = append(tags, C.GoString(tag))
|
||||
C.notmuch_tags_move_to_next(cTags)
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
// Create a new Query
|
||||
func (db *Database) Query(query string) (Query, error) {
|
||||
cQuery := C.CString(query)
|
||||
defer C.free(unsafe.Pointer(cQuery))
|
||||
nmQuery := C.notmuch_query_create(db.db, cQuery)
|
||||
if nmQuery == nil {
|
||||
return Query{}, STATUS_OUT_OF_MEMORY
|
||||
}
|
||||
q := Query{
|
||||
query: nmQuery,
|
||||
}
|
||||
return q, nil
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
//go:build notmuch
|
||||
// +build notmuch
|
||||
|
||||
package notmuch
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lnotmuch
|
||||
|
||||
#include <notmuch.h>
|
||||
|
||||
*/
|
||||
import "C"
|
||||
import "time"
|
||||
|
||||
type Directory struct {
|
||||
dir *C.notmuch_directory_t
|
||||
}
|
||||
|
||||
func (dir *Directory) SetModifiedTime(t time.Time) error {
|
||||
cTime := C.time_t(t.Unix())
|
||||
return errorWrap(C.notmuch_directory_set_mtime(dir.dir, cTime))
|
||||
}
|
||||
|
||||
func (dir *Directory) ModifiedTime() time.Time {
|
||||
cTime := C.notmuch_directory_get_mtime(dir.dir)
|
||||
return time.Unix(int64(cTime), 0)
|
||||
}
|
||||
|
||||
func (dir *Directory) Filenames() []string {
|
||||
cFilenames := C.notmuch_directory_get_child_files(dir.dir)
|
||||
defer C.notmuch_filenames_destroy(cFilenames)
|
||||
|
||||
filenames := []string{}
|
||||
for C.notmuch_filenames_valid(cFilenames) > 0 {
|
||||
filename := C.notmuch_filenames_get(cFilenames)
|
||||
filenames = append(filenames, C.GoString(filename))
|
||||
C.notmuch_filenames_move_to_next(cFilenames)
|
||||
}
|
||||
return filenames
|
||||
}
|
||||
|
||||
func (dir *Directory) Directories() []string {
|
||||
cFilenames := C.notmuch_directory_get_child_directories(dir.dir)
|
||||
defer C.notmuch_filenames_destroy(cFilenames)
|
||||
|
||||
filenames := []string{}
|
||||
for C.notmuch_filenames_valid(cFilenames) > 0 {
|
||||
filename := C.notmuch_filenames_get(cFilenames)
|
||||
filenames = append(filenames, C.GoString(filename))
|
||||
C.notmuch_filenames_move_to_next(cFilenames)
|
||||
}
|
||||
return filenames
|
||||
}
|
||||
|
||||
// Delete deletes a directory document from the database and destroys
|
||||
// the underlying object. Any child directories and files must have been
|
||||
// deleted firs the caller
|
||||
func (dir *Directory) Delete() error {
|
||||
return errorWrap(C.notmuch_directory_delete(dir.dir))
|
||||
}
|
||||
|
||||
func (dir *Directory) Close() {
|
||||
C.notmuch_directory_destroy(dir.dir)
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
//go:build notmuch
|
||||
// +build notmuch
|
||||
|
||||
package notmuch
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lnotmuch
|
||||
|
||||
#include <notmuch.h>
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// Status codes used for the return values of most functions
|
||||
type Status int
|
||||
|
||||
const (
|
||||
STATUS_SUCCESS Status = C.NOTMUCH_STATUS_SUCCESS
|
||||
STATUS_OUT_OF_MEMORY Status = C.NOTMUCH_STATUS_OUT_OF_MEMORY
|
||||
STATUS_READ_ONLY_DATABASE Status = C.NOTMUCH_STATUS_READ_ONLY_DATABASE
|
||||
STATUS_XAPIAN_EXCEPTION Status = C.NOTMUCH_STATUS_XAPIAN_EXCEPTION
|
||||
STATUS_FILE_ERROR Status = C.NOTMUCH_STATUS_FILE_ERROR
|
||||
STATUS_FILE_NOT_EMAIL Status = C.NOTMUCH_STATUS_FILE_NOT_EMAIL
|
||||
STATUS_DUPLICATE_MESSAGE_ID Status = C.NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID
|
||||
STATUS_NULL_POINTER Status = C.NOTMUCH_STATUS_NULL_POINTER
|
||||
STATUS_TAG_TOO_LONG Status = C.NOTMUCH_STATUS_TAG_TOO_LONG
|
||||
STATUS_UNBALANCED_FREEZE_THAW Status = C.NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW
|
||||
STATUS_UNBALANCED_ATOMIC Status = C.NOTMUCH_STATUS_UNBALANCED_ATOMIC
|
||||
STATUS_UNSUPPORTED_OPERATION Status = C.NOTMUCH_STATUS_UNSUPPORTED_OPERATION
|
||||
STATUS_UPGRADE_REQUIRED Status = C.NOTMUCH_STATUS_UPGRADE_REQUIRED
|
||||
STATUS_PATH_ERROR Status = C.NOTMUCH_STATUS_PATH_ERROR
|
||||
STATUS_IGNORED Status = C.NOTMUCH_STATUS_IGNORED
|
||||
STATUS_ILLEGAL_ARGUMENT Status = C.NOTMUCH_STATUS_ILLEGAL_ARGUMENT
|
||||
STATUS_MALFORMED_CRYPTO_PROTOCOL Status = C.NOTMUCH_STATUS_MALFORMED_CRYPTO_PROTOCOL
|
||||
STATUS_FAILED_CRYPTO_CONTEXT_CREATION Status = C.NOTMUCH_STATUS_FAILED_CRYPTO_CONTEXT_CREATION
|
||||
STATUS_UNKNOWN_CRYPTO_PROTOCOL Status = C.NOTMUCH_STATUS_UNKNOWN_CRYPTO_PROTOCOL
|
||||
STATUS_NO_CONFIG Status = C.NOTMUCH_STATUS_NO_CONFIG
|
||||
STATUS_NO_DATABASE Status = C.NOTMUCH_STATUS_NO_DATABASE
|
||||
STATUS_DATABASE_EXISTS Status = C.NOTMUCH_STATUS_DATABASE_EXISTS
|
||||
STATUS_BAD_QUERY_SYNTAX Status = C.NOTMUCH_STATUS_BAD_QUERY_SYNTAX
|
||||
STATUS_NO_MAIL_ROOT Status = C.NOTMUCH_STATUS_NO_MAIL_ROOT
|
||||
STATUS_CLOSED_DATABASE Status = C.NOTMUCH_STATUS_CLOSED_DATABASE
|
||||
)
|
||||
|
||||
func (s Status) Error() string {
|
||||
status := C.notmuch_status_to_string(C.notmuch_status_t(s))
|
||||
return C.GoString(status)
|
||||
}
|
||||
|
||||
func errorWrap(st C.notmuch_status_t) error {
|
||||
if Status(st) == STATUS_SUCCESS {
|
||||
return nil
|
||||
}
|
||||
return Status(st)
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
//go:build notmuch
|
||||
// +build notmuch
|
||||
|
||||
package notmuch
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lnotmuch
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <notmuch.h>
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type Message struct {
|
||||
message *C.notmuch_message_t
|
||||
}
|
||||
|
||||
// Close frees resources associated with the message
|
||||
func (m *Message) Close() {
|
||||
C.notmuch_message_destroy(m.message)
|
||||
}
|
||||
|
||||
// ID returns the message ID
|
||||
func (m *Message) ID() string {
|
||||
cID := C.notmuch_message_get_message_id(m.message)
|
||||
return C.GoString(cID)
|
||||
}
|
||||
|
||||
// ThreadID returns the thread ID of the message
|
||||
func (m *Message) ThreadID() string {
|
||||
cID := C.notmuch_message_get_thread_id(m.message)
|
||||
return C.GoString(cID)
|
||||
}
|
||||
|
||||
func (m *Message) Replies() Messages {
|
||||
cMessages := C.notmuch_message_get_replies(m.message)
|
||||
return Messages{
|
||||
messages: cMessages,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Message) TotalFiles() int {
|
||||
return int(C.notmuch_message_count_files(m.message))
|
||||
}
|
||||
|
||||
// Filename returns a single filename associated with the message. If the
|
||||
// message has multiple filenames, the return value will be arbitrarily chosen
|
||||
func (m *Message) Filename() string {
|
||||
cFilename := C.notmuch_message_get_filename(m.message)
|
||||
return C.GoString(cFilename)
|
||||
}
|
||||
|
||||
func (m *Message) Filenames() []string {
|
||||
cFilenames := C.notmuch_message_get_filenames(m.message)
|
||||
defer C.notmuch_filenames_destroy(cFilenames)
|
||||
|
||||
filenames := []string{}
|
||||
for C.notmuch_filenames_valid(cFilenames) > 0 {
|
||||
filename := C.notmuch_filenames_get(cFilenames)
|
||||
filenames = append(filenames, C.GoString(filename))
|
||||
C.notmuch_filenames_move_to_next(cFilenames)
|
||||
}
|
||||
return filenames
|
||||
}
|
||||
|
||||
// TODO is this needed?
|
||||
// func (m *Message) Reindex() error {
|
||||
//
|
||||
// }
|
||||
|
||||
type Flag int
|
||||
|
||||
const (
|
||||
MESSAGE_FLAG_MATCH Flag = iota
|
||||
MESSAGE_FLAG_EXCLUDED
|
||||
MESSAGE_FLAG_GHOST
|
||||
)
|
||||
|
||||
func (m *Message) Flag(flag Flag) (bool, error) {
|
||||
var ok C.notmuch_bool_t
|
||||
cFlag := C.notmuch_message_flag_t(flag)
|
||||
err := errorWrap(C.notmuch_message_get_flag_st(m.message, cFlag, &ok))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if ok == 0 {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// TODO why does this exist??
|
||||
// func (m *Message) SetFlag(flag Flag) {
|
||||
//
|
||||
// }
|
||||
|
||||
func (m *Message) Date() time.Time {
|
||||
cTime := C.notmuch_message_get_date(m.message)
|
||||
return time.Unix(int64(cTime), 0)
|
||||
}
|
||||
|
||||
func (m *Message) Header(field string) string {
|
||||
cField := C.CString(field)
|
||||
defer C.free(unsafe.Pointer(cField))
|
||||
cHeader := C.notmuch_message_get_header(m.message, cField)
|
||||
return C.GoString(cHeader)
|
||||
}
|
||||
|
||||
func (m *Message) Tags() []string {
|
||||
cTags := C.notmuch_message_get_tags(m.message)
|
||||
defer C.notmuch_tags_destroy(cTags)
|
||||
|
||||
tags := []string{}
|
||||
for C.notmuch_tags_valid(cTags) > 0 {
|
||||
tag := C.notmuch_tags_get(cTags)
|
||||
tags = append(tags, C.GoString(tag))
|
||||
C.notmuch_tags_move_to_next(cTags)
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
func (m *Message) AddTag(tag string) error {
|
||||
cTag := C.CString(tag)
|
||||
defer C.free(unsafe.Pointer(cTag))
|
||||
|
||||
return errorWrap(C.notmuch_message_add_tag(m.message, cTag))
|
||||
}
|
||||
|
||||
func (m *Message) RemoveTag(tag string) error {
|
||||
cTag := C.CString(tag)
|
||||
defer C.free(unsafe.Pointer(cTag))
|
||||
|
||||
return errorWrap(C.notmuch_message_remove_tag(m.message, cTag))
|
||||
}
|
||||
|
||||
func (m *Message) RemoveAllTags() error {
|
||||
return errorWrap(C.notmuch_message_remove_all_tags(m.message))
|
||||
}
|
||||
|
||||
// SyncTagsToMaildirFlags adds/removes the appropriate tags to the maildir
|
||||
// filename
|
||||
func (m *Message) SyncTagsToMaildirFlags() error {
|
||||
return errorWrap(C.notmuch_message_tags_to_maildir_flags(m.message))
|
||||
}
|
||||
|
||||
// SyncMaildirFlagsToTags syncs the current maildir flags to the notmuch tags
|
||||
func (m *Message) SyncMaildirFlagsToTags() error {
|
||||
return errorWrap(C.notmuch_message_maildir_flags_to_tags(m.message))
|
||||
}
|
||||
|
||||
func (m *Message) HasMaildirFlag(flag rune) (bool, error) {
|
||||
var ok C.notmuch_bool_t
|
||||
err := errorWrap(C.notmuch_message_has_maildir_flag_st(m.message, C.char(flag), &ok))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if ok == 0 {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (m *Message) Freeze() error {
|
||||
return errorWrap(C.notmuch_message_freeze(m.message))
|
||||
}
|
||||
|
||||
func (m *Message) Thaw() error {
|
||||
return errorWrap(C.notmuch_message_thaw(m.message))
|
||||
}
|
||||
|
||||
func (m *Message) Property(key string) (string, error) {
|
||||
var (
|
||||
cKey *C.char
|
||||
cValue *C.char
|
||||
)
|
||||
defer C.free(unsafe.Pointer(cKey))
|
||||
defer C.free(unsafe.Pointer(cValue))
|
||||
cKey = C.CString(key)
|
||||
err := errorWrap(C.notmuch_message_get_property(m.message, cKey, &cValue)) //nolint:gocritic // see note in notmuch.go
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return C.GoString(cValue), nil
|
||||
}
|
||||
|
||||
func (m *Message) AddProperty(key string, value string) error {
|
||||
var (
|
||||
cKey *C.char
|
||||
cValue *C.char
|
||||
)
|
||||
defer C.free(unsafe.Pointer(cKey))
|
||||
defer C.free(unsafe.Pointer(cValue))
|
||||
cKey = C.CString(key)
|
||||
cValue = C.CString(value)
|
||||
return errorWrap(C.notmuch_message_add_property(m.message, cKey, cValue))
|
||||
}
|
||||
|
||||
func (m *Message) RemoveProperty(key string, value string) error {
|
||||
var (
|
||||
cKey *C.char
|
||||
cValue *C.char
|
||||
)
|
||||
defer C.free(unsafe.Pointer(cKey))
|
||||
defer C.free(unsafe.Pointer(cValue))
|
||||
cKey = C.CString(key)
|
||||
cValue = C.CString(value)
|
||||
return errorWrap(C.notmuch_message_remove_property(m.message, cKey, cValue))
|
||||
}
|
||||
|
||||
func (m *Message) RemoveAllProperties(key string) error {
|
||||
var cKey *C.char
|
||||
defer C.free(unsafe.Pointer(cKey))
|
||||
cKey = C.CString(key)
|
||||
return errorWrap(C.notmuch_message_remove_all_properties(m.message, cKey))
|
||||
}
|
||||
|
||||
func (m *Message) RemoveAllPropertiesWithPrefix(prefix string) error {
|
||||
var cPrefix *C.char
|
||||
defer C.free(unsafe.Pointer(cPrefix))
|
||||
cPrefix = C.CString(prefix)
|
||||
return errorWrap(C.notmuch_message_remove_all_properties_with_prefix(m.message, cPrefix))
|
||||
}
|
||||
|
||||
func (m *Message) Properties(key string, exact bool) *Properties {
|
||||
var (
|
||||
cKey *C.char
|
||||
cExact C.int
|
||||
)
|
||||
defer C.free(unsafe.Pointer(cKey))
|
||||
if exact {
|
||||
cExact = 1
|
||||
}
|
||||
|
||||
cKey = C.CString(key)
|
||||
props := C.notmuch_message_get_properties(m.message, cKey, cExact)
|
||||
|
||||
return &Properties{
|
||||
properties: props,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Message) CountProperties(key string) (int, error) {
|
||||
var (
|
||||
cKey *C.char
|
||||
cCount C.uint
|
||||
)
|
||||
defer C.free(unsafe.Pointer(cKey))
|
||||
cKey = C.CString(key)
|
||||
err := errorWrap(C.notmuch_message_count_properties(m.message, cKey, &cCount))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(cCount), nil
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
//go:build notmuch
|
||||
// +build notmuch
|
||||
|
||||
package notmuch
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lnotmuch
|
||||
|
||||
#include <notmuch.h>
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
type Messages struct {
|
||||
message *C.notmuch_message_t
|
||||
messages *C.notmuch_messages_t
|
||||
}
|
||||
|
||||
// Next advances the Messages iterator to the next message. Next returns false if
|
||||
// no more messages are available
|
||||
func (m *Messages) Next() bool {
|
||||
if C.notmuch_messages_valid(m.messages) == 0 {
|
||||
return false
|
||||
}
|
||||
m.message = C.notmuch_messages_get(m.messages)
|
||||
C.notmuch_messages_move_to_next(m.messages)
|
||||
return true
|
||||
}
|
||||
|
||||
// Message returns the current message in the iterator
|
||||
func (m *Messages) Message() Message {
|
||||
return Message{
|
||||
message: m.message,
|
||||
}
|
||||
}
|
||||
|
||||
// Close frees memory associated with a Messages iterator. This method is not
|
||||
// strictly necessary to call, as the resources will be freed when the Query
|
||||
// associated with the Messages object is freed.
|
||||
func (m *Messages) Close() {
|
||||
C.notmuch_messages_destroy(m.messages)
|
||||
}
|
||||
|
||||
// Tags returns a slice of all tags in the message list. WARNING: After calling
|
||||
// tags, the message list can no longer be iterated; a new list must be created
|
||||
// to iterate after calling Tags
|
||||
func (m *Messages) Tags() []string {
|
||||
cTags := C.notmuch_messages_collect_tags(m.messages)
|
||||
defer C.notmuch_tags_destroy(cTags)
|
||||
|
||||
tags := []string{}
|
||||
for C.notmuch_tags_valid(cTags) > 0 {
|
||||
tag := C.notmuch_tags_get(cTags)
|
||||
tags = append(tags, C.GoString(tag))
|
||||
C.notmuch_tags_move_to_next(cTags)
|
||||
}
|
||||
return tags
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
//go:build notmuch
|
||||
// +build notmuch
|
||||
|
||||
package notmuch
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lnotmuch
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <notmuch.h>
|
||||
|
||||
#if !LIBNOTMUCH_CHECK_VERSION(5, 6, 0)
|
||||
#error "aerc requires libnotmuch.so.5.6 or later"
|
||||
#endif
|
||||
|
||||
*/
|
||||
import "C"
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
MAJOR_VERSION = C.LIBNOTMUCH_MAJOR_VERSION
|
||||
MINOR_VERSION = C.LIBNOTMUCH_MINOR_VERSION
|
||||
MICRO_VERSION = C.LIBNOTMUCH_MICRO_VERSION
|
||||
)
|
||||
|
||||
func Version() string {
|
||||
return fmt.Sprintf("%d.%d.%d", MAJOR_VERSION, MINOR_VERSION, MICRO_VERSION)
|
||||
}
|
||||
|
||||
// NOTE: Any CGO call which passes a reference to a pointer (**object) will fail
|
||||
// gocritic:dupSubExpr. All of these calls are set to be ignored by the linter
|
||||
// Reference: https://github.com/go-critic/go-critic/issues/897
|
||||
@@ -0,0 +1,39 @@
|
||||
//go:build notmuch
|
||||
// +build notmuch
|
||||
|
||||
package notmuch
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lnotmuch
|
||||
|
||||
#include <notmuch.h>
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
type Properties struct {
|
||||
key *C.char
|
||||
value *C.char
|
||||
properties *C.notmuch_message_properties_t
|
||||
}
|
||||
|
||||
// Next advances the Properties iterator to the next property. Next returns false if
|
||||
// no more properties are available
|
||||
func (p *Properties) Next() bool {
|
||||
if C.notmuch_message_properties_valid(p.properties) == 0 {
|
||||
return false
|
||||
}
|
||||
p.key = C.notmuch_message_properties_key(p.properties)
|
||||
p.value = C.notmuch_message_properties_value(p.properties)
|
||||
C.notmuch_message_properties_move_to_next(p.properties)
|
||||
return true
|
||||
}
|
||||
|
||||
// Returns the key of the current iterator location
|
||||
func (p *Properties) Key() string {
|
||||
return C.GoString(p.key)
|
||||
}
|
||||
|
||||
func (p *Properties) Value() string {
|
||||
return C.GoString(p.value)
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
//go:build notmuch
|
||||
// +build notmuch
|
||||
|
||||
package notmuch
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lnotmuch
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <notmuch.h>
|
||||
|
||||
*/
|
||||
import "C"
|
||||
import "unsafe"
|
||||
|
||||
type ExcludeMode int
|
||||
|
||||
const (
|
||||
EXCLUDE_FLAG ExcludeMode = C.NOTMUCH_EXCLUDE_FLAG
|
||||
EXCLUDE_TRUE ExcludeMode = C.NOTMUCH_EXCLUDE_TRUE
|
||||
EXCLUDE_FALSE ExcludeMode = C.NOTMUCH_EXCLUDE_FALSE
|
||||
EXCLUDE_ALL ExcludeMode = C.NOTMUCH_EXCLUDE_ALL
|
||||
)
|
||||
|
||||
type SortMode int
|
||||
|
||||
const (
|
||||
SORT_OLDEST_FIRST SortMode = C.NOTMUCH_SORT_OLDEST_FIRST
|
||||
SORT_NEWEST_FIRST SortMode = C.NOTMUCH_SORT_NEWEST_FIRST
|
||||
SORT_MESSAGE_ID SortMode = C.NOTMUCH_SORT_MESSAGE_ID
|
||||
SORT_UNSORTED SortMode = C.NOTMUCH_SORT_UNSORTED
|
||||
)
|
||||
|
||||
type Query struct {
|
||||
query *C.notmuch_query_t
|
||||
}
|
||||
|
||||
// Close frees resources associated with a query. Closing a query release all
|
||||
// resources associated with any underlying search (Threads, Messages, etc)
|
||||
func (q *Query) Close() {
|
||||
C.notmuch_query_destroy(q.query)
|
||||
}
|
||||
|
||||
// Return the string of the query
|
||||
func (q *Query) String() string {
|
||||
return C.GoString(C.notmuch_query_get_query_string(q.query))
|
||||
}
|
||||
|
||||
// Returns the Database associated with the query. The Path, Config, and Profile
|
||||
// values will not be set on the returned valued
|
||||
func (q *Query) Database() Database {
|
||||
db := C.notmuch_query_get_database(q.query)
|
||||
return Database{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
// Exclude sets the exclusion mode.
|
||||
func (q *Query) Exclude(val ExcludeMode) {
|
||||
cVal := C.notmuch_exclude_t(val)
|
||||
C.notmuch_query_set_omit_excluded(q.query, cVal)
|
||||
}
|
||||
|
||||
// Sort sets the sort order of the results
|
||||
func (q *Query) Sort(sort SortMode) {
|
||||
cVal := C.notmuch_sort_t(sort)
|
||||
C.notmuch_query_set_sort(q.query, cVal)
|
||||
}
|
||||
|
||||
// SortMode returns the current sort order of the results
|
||||
func (q *Query) SortMode() SortMode {
|
||||
return SortMode(C.notmuch_query_get_sort(q.query))
|
||||
}
|
||||
|
||||
// ExcludeTag adds a tag to exclude from the results
|
||||
func (q *Query) ExcludeTag(tag string) error {
|
||||
cTag := C.CString(tag)
|
||||
defer C.free(unsafe.Pointer(cTag))
|
||||
return errorWrap(C.notmuch_query_add_tag_exclude(q.query, cTag))
|
||||
}
|
||||
|
||||
// Threads returns an iterator over the threads that match the query
|
||||
func (q *Query) Threads() (Threads, error) {
|
||||
var cThreads *C.notmuch_threads_t
|
||||
err := errorWrap(C.notmuch_query_search_threads(q.query, &cThreads)) //nolint:gocritic // see note in notmuch.go
|
||||
if err != nil {
|
||||
return Threads{}, err
|
||||
}
|
||||
threads := Threads{
|
||||
threads: cThreads,
|
||||
}
|
||||
return threads, nil
|
||||
}
|
||||
|
||||
// Messages returns an iterator over the messages that match the query
|
||||
func (q *Query) Messages() (Messages, error) {
|
||||
var cMessages *C.notmuch_messages_t
|
||||
err := errorWrap(C.notmuch_query_search_messages(q.query, &cMessages)) //nolint:gocritic // see note in notmuch.go
|
||||
if err != nil {
|
||||
return Messages{}, err
|
||||
}
|
||||
messages := Messages{
|
||||
messages: cMessages,
|
||||
}
|
||||
return messages, nil
|
||||
}
|
||||
|
||||
// CountMessages returns the number of messages matching the query
|
||||
func (q *Query) CountMessages() (int, error) {
|
||||
var count C.uint
|
||||
err := errorWrap(C.notmuch_query_count_messages(q.query, &count))
|
||||
return int(count), err
|
||||
}
|
||||
|
||||
// CountThreads returns the number of threads matching the query
|
||||
func (q *Query) CountThreads() (int, error) {
|
||||
var count C.uint
|
||||
err := errorWrap(C.notmuch_query_count_threads(q.query, &count))
|
||||
return int(count), err
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
//go:build notmuch
|
||||
// +build notmuch
|
||||
|
||||
package notmuch
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lnotmuch
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <notmuch.h>
|
||||
|
||||
*/
|
||||
import "C"
|
||||
import "time"
|
||||
|
||||
type Thread struct {
|
||||
thread *C.notmuch_thread_t
|
||||
}
|
||||
|
||||
// ID returns the thread ID
|
||||
func (t *Thread) ID() string {
|
||||
cID := C.notmuch_thread_get_thread_id(t.thread)
|
||||
return C.GoString(cID)
|
||||
}
|
||||
|
||||
// TotalMessages returns the total number of messages in the thread
|
||||
func (t *Thread) TotalMessages() int {
|
||||
return int(C.notmuch_thread_get_total_messages(t.thread))
|
||||
}
|
||||
|
||||
// TotalMessages returns the total number of files in the thread
|
||||
func (t *Thread) TotalFiles() int {
|
||||
return int(C.notmuch_thread_get_total_files(t.thread))
|
||||
}
|
||||
|
||||
// TopLevelMessages returns an iterator over the top level messages in the
|
||||
// thread. Messages are sorted oldest-first
|
||||
func (t *Thread) TopLevelMessages() Messages {
|
||||
cMessages := C.notmuch_thread_get_toplevel_messages(t.thread)
|
||||
return Messages{
|
||||
messages: cMessages,
|
||||
}
|
||||
}
|
||||
|
||||
// Messages returns an iterator over the messages in the thread. Messages are
|
||||
// sorted oldest-first
|
||||
func (t *Thread) Messages() Messages {
|
||||
cMessages := C.notmuch_thread_get_messages(t.thread)
|
||||
return Messages{
|
||||
messages: cMessages,
|
||||
}
|
||||
}
|
||||
|
||||
// Matches returns the number of messages in the thread that matched the query
|
||||
func (t *Thread) Matches() int {
|
||||
return int(C.notmuch_thread_get_matched_messages(t.thread))
|
||||
}
|
||||
|
||||
// Returns a string of authors of the thread
|
||||
func (t *Thread) Authors() string {
|
||||
cAuthors := C.notmuch_thread_get_authors(t.thread)
|
||||
return C.GoString(cAuthors)
|
||||
}
|
||||
|
||||
// Returns the subject of the thread
|
||||
func (t *Thread) Subject() string {
|
||||
cSubject := C.notmuch_thread_get_subject(t.thread)
|
||||
return C.GoString(cSubject)
|
||||
}
|
||||
|
||||
// Returns the sent-date of the oldest message in the thread
|
||||
func (t *Thread) OldestDate() time.Time {
|
||||
cTime := C.notmuch_thread_get_oldest_date(t.thread)
|
||||
return time.Unix(int64(cTime), 0)
|
||||
}
|
||||
|
||||
// Returns the sent-date of the newest message in the thread
|
||||
func (t *Thread) NewestDate() time.Time {
|
||||
cTime := C.notmuch_thread_get_newest_date(t.thread)
|
||||
return time.Unix(int64(cTime), 0)
|
||||
}
|
||||
|
||||
// Tags returns a slice of all tags in the thread
|
||||
func (t *Thread) Tags() []string {
|
||||
cTags := C.notmuch_thread_get_tags(t.thread)
|
||||
defer C.notmuch_tags_destroy(cTags)
|
||||
|
||||
tags := []string{}
|
||||
for C.notmuch_tags_valid(cTags) > 0 {
|
||||
tag := C.notmuch_tags_get(cTags)
|
||||
tags = append(tags, C.GoString(tag))
|
||||
C.notmuch_tags_move_to_next(cTags)
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
func (t *Thread) Close() {
|
||||
C.notmuch_thread_destroy(t.thread)
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
//go:build notmuch
|
||||
// +build notmuch
|
||||
|
||||
package notmuch
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lnotmuch
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <notmuch.h>
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// Threads is an iterator over a set of threads.
|
||||
type Threads struct {
|
||||
thread *C.notmuch_thread_t
|
||||
threads *C.notmuch_threads_t
|
||||
}
|
||||
|
||||
// Next advances the Threads iterator to the next thread. Next returns false if
|
||||
// no more threads are available
|
||||
func (t *Threads) Next() bool {
|
||||
if C.notmuch_threads_valid(t.threads) == 0 {
|
||||
return false
|
||||
}
|
||||
t.thread = C.notmuch_threads_get(t.threads)
|
||||
C.notmuch_threads_move_to_next(t.threads)
|
||||
return true
|
||||
}
|
||||
|
||||
// Thread returns the current thread in the iterator
|
||||
func (t *Threads) Thread() Thread {
|
||||
return Thread{
|
||||
thread: t.thread,
|
||||
}
|
||||
}
|
||||
|
||||
// Close frees memory associated with a Threads iterator. This method is not
|
||||
// strictly necessary to call, as the resources will be freed when the Query
|
||||
// associated with the Threads object is freed.
|
||||
func (t *Threads) Close() {
|
||||
C.notmuch_threads_destroy(t.threads)
|
||||
}
|
||||
Reference in New Issue
Block a user