-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Haskell binding to Notmuch, the mail indexer -- -- Binding to the notmuch mail indexer, providing a hopefully somewhat -- typesafe way to search your email. @package notmuch @version 0.3.1 -- | Stuff that we don't want to export by default, but that we do want to -- expose in the library interface. module Notmuch.Util type Prism s t a b = forall p f. (Choice p, Applicative f) => p a (f b) -> p s (f t) type Prism' s a = Prism s s a a type Lens' a b = forall f. Functor f => (b -> f b) -> (a -> f a) review :: MonadReader b m => Prism' t b -> m t -- | Variant of bracket that works with ExceptT and allows resource -- acquisition to fail, propagating the error. If resource finalisation -- fails, the error is discarded. bracketT :: (MonadError e m, MonadIO m) => ExceptT e IO a -> (a -> ExceptT e IO b) -> (a -> ExceptT e IO c) -> m c -- | High-level interface to the notmuch mail indexer. -- -- Example program to add/remove a tag on all messages matching a query: -- --
--   main :: IO ()
--   main = getArgs >>= \args -> case args of
--     [path, expr, '+':tag] -> go path expr tag messageAddTag
--     [path, expr, '-':tag] -> go path expr tag messageRemoveTag
--     _ -> die "usage: hs-notmuch-tag-set DB-DIR SEARCH-TERM +TAG|-TAG"
--     where
--       go path expr tag f =
--         runExceptT (do
--           db <- databaseOpen path
--           query db (Bare expr) >>= messages >>= traverse_ (f (fromString tag))
--         ) >>= either (die . (show :: Status -> String)) pure
--   
-- --

File descriptor exhaustion

-- -- Some Message operations cause the message file to be opened -- (and remain open until the object gets garbage collected): -- -- -- -- If the RTS is using a multi-generation collector (the default), and if -- you are working with lots of messages, you may hit max open -- files limits. The best way to avoid this is to avoid the scenarios -- outlined above. Alternative approaches that could help include: -- -- module Notmuch -- | Open a database. The database will be closed and associated resources -- freed upon garbage collection. -- -- The mode is determined by usage. Because read-only functions also work -- on read-write databases, databaseOpenReadOnly is also provided -- for convenience. databaseOpen :: (Mode a, AsNotmuchError e, MonadError e m, MonadIO m) => FilePath -> m (Database a) -- | Convenience function for opening a database read-only databaseOpenReadOnly :: (AsNotmuchError e, MonadError e m, MonadIO m) => FilePath -> m (Database RO) -- | Get the path of the database databasePath :: Database a -> FilePath -- | Database format version of the given database. databaseVersion :: MonadIO m => Database a -> m Int -- | A database handle. The database will be closed and freed when it is -- garbage collected. -- -- Use query to perform a search or findMessage to -- search for a particular message. -- -- The Database type carries a phantom for the database mode, -- which is propgated to derived Query, Thread and -- Message objects. This is used to prevent write operations being -- performed against a read-only database. data Database (a :: DatabaseMode) -- | This is an internal class whose instances are the promoted -- DatabaseMode constructors. class Mode a data DatabaseMode DatabaseModeReadOnly :: DatabaseMode DatabaseModeReadWrite :: DatabaseMode -- | Convenience synonym for the promoted DatabaseModeReadOnly -- constructor. type RO = 'DatabaseModeReadOnly -- | Convenience synonym for the promoted DatabaseModeReadWrite -- constructor. type RW = 'DatabaseModeReadWrite -- | Query object. Cleaned up when garbage collected. -- -- Use messages or threads to get the results. -- -- The Query type carries a phantom for the database mode, so -- that write operations on messages derived from it are restricted to -- read/write database sessions. data Query (a :: DatabaseMode) -- | Query the database. To retrieve results from a Query, use -- threads or messages. query :: MonadIO m => Database a -> SearchTerm -> m (Query a) -- | Count the number of messages matching a query. -- -- Complexity: same as the underlying Xapian search… queryCountMessages :: (AsNotmuchError e, MonadError e m, MonadIO m) => Query a -> m Int -- | Count the number of threads matching a query. -- -- Θ(n) in the number of messages! queryCountThreads :: (AsNotmuchError e, MonadError e m, MonadIO m) => Query a -> m Int -- | Search expression. Use Bare if you want to use a query string -- as-is (see also notmuch-search-terms(7)). -- -- Use show to stringify a SearchTerm. data SearchTerm FreeForm :: String -> SearchTerm From :: String -> SearchTerm To :: String -> SearchTerm Subject :: String -> SearchTerm Attachment :: String -> SearchTerm Tag :: Tag -> SearchTerm Id :: MessageId -> SearchTerm Thread :: ThreadId -> SearchTerm Folder :: String -> SearchTerm Path :: String -> SearchTerm Date :: String -> String -> SearchTerm Asterisk :: SearchTerm And :: SearchTerm -> SearchTerm -> SearchTerm Or :: SearchTerm -> SearchTerm -> SearchTerm Xor :: SearchTerm -> SearchTerm -> SearchTerm Not :: SearchTerm -> SearchTerm Bare :: String -> SearchTerm -- | Objects with an associated ThreadId class HasThread a threadId :: (HasThread a, MonadIO m) => a -> m ThreadId -- | Thread object. Cleaned up when garbage collected. -- -- Use messages to get the messages of a thread. -- -- The Thread type carries a phantom for the database mode, so -- that write operations on messages derived from it are restricted to -- read/write database sessions. data Thread (a :: DatabaseMode) -- | Returns only messages in a thread which are not replies to other -- messages in the thread. threadToplevelMessages :: (AsNotmuchError e, MonadError e m, MonadIO m) => Thread a -> m [Message 0 a] -- | O(1) Date of the newest message in a SearchTerm. threadNewestDate :: MonadIO m => Thread a -> m UTCTime -- | Returns the subject of the first message in the query results that -- belongs to this thread. threadSubject :: MonadIO m => Thread a -> m ByteString -- | Return authors of a thread. These are split into: -- -- threadAuthors :: MonadIO m => Thread a -> m ThreadAuthors -- | O(1) count of messages in the thread. threadTotalMessages :: MonadIO m => Thread a -> m Int -- | Thread identifier generated and used by libnotmuch. type ThreadId = ByteString -- | Objects with associated threads class HasThreads a threads :: (HasThreads a, AsNotmuchError e, MonadError e m, MonadIO m) => a mode -> m [Thread mode] -- | Authors belonging to messages in a query result of a thread ordered by -- date. data ThreadAuthors -- | Author of a message. type Author = Text -- | Lens to matched authors. See also threadAuthors. matchedAuthors :: Lens' ThreadAuthors [Author] -- | Lens to unmatched authors. See also threadAuthors. unmatchedAuthors :: Lens' ThreadAuthors [Author] -- | Look for a particular message in the database. findMessage :: (AsNotmuchError e, MonadError e m, MonadIO m) => Database a -> MessageId -> m (Maybe (Message 0 a)) -- | Objects with associated messages. class HasMessages a messages :: (HasMessages a, AsNotmuchError e, MonadError e m, MonadIO m) => a mode -> m [Message 0 mode] -- | Message object. Cleaned up when garbage collected. -- -- The Message type carries a phantom for the database mode, so -- that write operations are restricted to read/write database sessions. -- -- There is also a phantom type parameter for the degree of frozenness of -- the message. Tag operations on a frozen message are atomic, only -- becoming visible to other threads/processes after the thaw. The -- freeze/thaw behaviour is available via withFrozenMessage. data Message (n :: Nat) (a :: DatabaseMode) -- | Message-Id header value. type MessageId = ByteString -- | Get the message ID. messageId :: MonadIO m => Message n a -> m MessageId -- | Get the date the message was sent. messageDate :: MonadIO m => Message n a -> m UTCTime -- | Get the named header as a UTF-8 encoded string. Empty string if header -- is missing or Nothing on error. -- -- May open a file descriptor that will not be closed until the -- message gets garbage collected. messageHeader :: MonadIO m => ByteString -> Message n a -> m (Maybe ByteString) -- | Set tags for the message. Atomic. messageSetTags :: (MonadIO m, Foldable t) => t Tag -> Message 0 RW -> m () -- | Add the tag to a message. If adding/removing multiple tags, use -- messageSetTags to set the whole tag list atomically, or use -- withFrozenMessage to avoid inconsistent states when -- adding/removing tags. messageAddTag :: MonadIO m => Tag -> Message n RW -> m () -- | Remove the tag from a message. If adding/removing multiple tags, use -- messageSetTags to set the whole tag list atomically, or use -- withFrozenMessage to avoid inconsistent states when -- adding/removing tags. messageRemoveTag :: MonadIO m => Tag -> Message n RW -> m () -- | Freeze the message, run the given computation and return the result. -- The message is always thawed at the end. -- -- Have to start with Message 0 RW due to GHC type system -- limitation (type-level Nat is not inductive). withFrozenMessage :: (forall n. Message n RW -> IO a) -> Message 0 RW -> IO a -- | Get the filename of the message. messageFilename :: MonadIO m => Message n a -> m FilePath -- | Index a file with the default indexing options. (This binding does not -- yet provide a way to change the indexing options.) Returns the indexed -- message. -- -- If message has same message ID as another message in the database, the -- new filename will be added to the message and the existing message is -- returned. -- -- Possible errors include: -- -- indexFile :: (AsNotmuchError e, MonadError e m, MonadIO m) => Database RW -> FilePath -> m (Message 0 RW) -- | Remove a message filename. If the message has no more filenames return -- MessageRemoved, otherwise MessagePersists. -- -- The underlying routine (as of notmuch v0.28) returns -- NOTMUCH_STATUS_SUCCESS even when the given path does not -- exist, is not an internet message, or is not recorded in the database. -- Therefore removeFile also returns MessageRemoved in -- this scenario. This is particularly confusing when the -- Message-Id of the given file is known, but the the file -- itself is unknown. removeFile :: (AsNotmuchError e, MonadError e m, MonadIO m) => Database RW -> FilePath -> m RemoveResult -- | Result of a removeFile operation. data RemoveResult MessageRemoved :: RemoveResult MessagePersists :: RemoveResult -- | Objects with tags class HasTags a tags :: (HasTags a, MonadIO m) => a -> m [Tag] -- | Message tag. Use mkTag to construct a tag. Or use -- -XOverloadedStrings, but beware that the IsString -- instance is non-total. -- -- This data type avoid copying when passing tags to libnotmuch. -- But copies do occur when reading tags from a database. -- -- A previous experiment with interning showed no benefit. Tags are -- typically very short so the overhead erodes any advantage. data Tag -- | O(n) Just a tag, or Nothing if the string is -- too long -- -- Use UTF-8 encoding to include non-ASCII characters in a tag. mkTag :: ByteString -> Maybe Tag -- | O(1) getTag :: Tag -> ByteString -- | The maximum tag length. Defined as NOTMUCH_TAG_MAX in -- notmuch.h. tagMaxLen :: Int data Status StatusSuccess :: Status StatusOutOfMemory :: Status StatusReadOnlyDatabase :: Status StatusXapianException :: Status StatusFileError :: Status StatusFileNotEmail :: Status StatusDuplicateMessageId :: Status StatusNullPointer :: Status StatusTagTooLong :: Status StatusUnbalancedFreezeThaw :: Status StatusUnbalancedAtomic :: Status StatusUnsupportedOperation :: Status StatusUpgradeRequired :: Status StatusPathError :: Status StatusIgnored :: Status StatusIllegalArgument :: Status StatusMalformedCryptoProtocol :: Status StatusFailedCryptoContextCreation :: Status StatusUnknownCryptoProtocol :: Status StatusNoConfig :: Status StatusNoDatabase :: Status StatusDatabaseExists :: Status StatusBadQuerySyntax :: Status StatusNoMailRoot :: Status StatusLastStatus :: Status -- | Classy prism for injecting a libnotmuch status code. class AsNotmuchError s _NotmuchError :: AsNotmuchError s => Prism' s Status -- | The version of libnotmuch that hs-notmuch was -- built against. (The program could be running against a -- different version.) libnotmuchVersion :: Version instance Control.DeepSeq.NFData Notmuch.ThreadAuthors instance GHC.Generics.Generic Notmuch.ThreadAuthors instance GHC.Show.Show Notmuch.ThreadAuthors instance Notmuch.HasThread (Notmuch.Binding.Thread a) instance Notmuch.HasThread (Notmuch.Binding.Message n a) instance Notmuch.HasThreads Notmuch.Binding.Query instance Notmuch.HasMessages Notmuch.Binding.Query instance Notmuch.HasMessages Notmuch.Binding.Thread instance Notmuch.HasMessages (Notmuch.Binding.Message n) instance Notmuch.HasTags (Notmuch.Binding.Database a) instance Notmuch.HasTags (Notmuch.Binding.Thread a) instance Notmuch.HasTags (Notmuch.Binding.Message n a)