\input texinfo.tex    @c -*-texinfo-*-
@c %**start of header
@setfilename mu-scm.info
@settitle Mu-SCM User Manual

@c Use proper quote and backtick for code sections in PDF output
@c Cf. Texinfo manual 14.2
@set txicodequoteundirected
@set txicodequotebacktick

@documentencoding UTF-8
@c %**end of header

@include version.texi

@copying
Copyright @copyright{} 2025-@value{UPDATED-YEAR} Dirk-Jan C. Binnema

@quotation
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or
any later version published by the Free Software Foundation; with no
Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.  A
copy of the license is included in the section entitled ``GNU Free
Documentation License.''
@end quotation
@end copying

@titlepage
@title Mu-SCM - extending @t{mu} with Guile Scheme
@subtitle version  @value{VERSION}
@author Dirk-Jan C. Binnema

@c The following two commands start the copyright page.
@page
@vskip 0pt plus 1filll
@insertcopying
@end titlepage

@dircategory The Algorithmic Language Scheme
@direntry
* Mu-SCM: (mu-scm).        Guile support for the mu e-mail search engine
@end direntry

@contents

@ifnottex
@node Top
@top Mu-SCM Manual
@end ifnottex

@iftex
@node Welcome to @t{mu-scm}
@unnumbered Welcome to @t{mu-scm}
@end iftex

Welcome to @t{mu-scm}!

@t{mu} is a program for indexing and searching your e-mails. It can do so in
many different ways, but sometimes that may not be enough.

@t{mu-scm} is made for such cases. It embeds the Guile programming language into
@t{mu}. Guile is the @emph{GNU Ubiquitous Intelligent Language for Extensions} -
a version of the @emph{Scheme} programming language, the official GNU extension
language, and a member of the @emph{Lisp} family of programming languages --
like emacs-lisp, @emph{Racket}, Common Lisp.

@t{mu-scm} is replacing the older @t{mu-guile} bindings; some notable
differences are:
@itemize
@item No separate 'module', instead use mu itself:
This greatly reduces the number of 'moving parts' and mysterious errors for users
@item Automatically set up a reasonable environment:
@t{mu scm} simply reuses the user's @t{mu} configuration, simplifying setup
@item API improvements:
@t{mu-scm} has learned from @t{mu-guile} to make its APIs nicer to use
@item However, some parts are still missing:
@t{mu-scm} does not yet support all that @t{mu-guile} did. It's just getting
started.
@end itemize

If you're not familiar with Scheme or Lisp, @t{mu-scm} may be a fun way to learn
a bit more! Note: @t{mu-scm} is brand new and rather @strong{experimental} for
now, and APIs can still change without warning.

@menu
* Getting started::
* Shell::
* Scripts::
* API Reference with examples::

Appendices
* GNU Free Documentation License::  The license of this manual.

Indices
* Procedure Index::
* Variable Index::

@end menu

@node Getting started
@chapter Getting started

@menu
* Using distributions::
* Building it yourself::
* Starting the REPL::
* Listening on a Unix Domain Socket::
* Hooking up with GNU/Emacs and Geiser::
* Hooking up with Mu4e::
@end menu

This chapter walks you through the installation and basic setup.

@node Using distributions
@section Using distributions

At the time of writing, few distributions ship with an SCM-enabled @t{mu}, but
we know at least Guix@footnote{@url{https://guix.gnu.org/}}. For other
distributions, you need to build it yourself for now. Of course, this is fully
optional.

@node Building it yourself
@section Building it yourself

To build @t{mu} with SCM support, first you need to ensure you have installed
the required Guile development packages. The details of getting those vary
across environments / distributions, e.g.: on Fedora (as root):

@example
# dnf install guile30-devel
@end example

or on Debian/Ubuntu:
@example
$ sudo apt install guile-3.0-dev
@end example

With those packages in place, you can (re)build @t{mu} and @t{mu-scm} should be
built automatically if you did @emph{not} explicitly disable it.

Parts of @t{mu-scm} depend on @t{mu} being @emph{installed}, not just built;
however, you can still use it un-installed as well by setting an environment
variable @t{MU_SCM_DIR} to the source-directory, e.g.
@t{/home/user/sources/mu/scm}.

@node Starting the REPL
@section Starting the REPL

After installing @t{mu}, you can check the output of @command{mu info}. If
@t{mu-scm} is available, in the table you should find a line:
@example
| scm-support      | yes     | GNU Guile 3.x support (new)?          |
@end example

You can then start an interactive shell, also known as the
``REPL''@footnote{Read-Eval-Print-Loop}.
@cindex REPL

@example
$ mu scm
[....]
Welcome to the mu shell!

GNU Guile 3.0.9
Copyright (C) 1995-2023 Free Software Foundation, Inc.

Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.

Enter `,help' for help.
scheme@@(guile-user)>
@end example

Refer to the @xref{Shell} chapter to learn about the wonderful things you can do
in this shell.

@node Listening on a Unix Domain Socket
@section Listening on a Unix Domain Socket

Instead of using the interactive shell, it is also possible to expose the
REPL over a Unix domain socket, using the @t{--listen} flag.
@cindex Unix domain sockets

When you start @command{mu scm} with the @t{--listen} flag, it prints a
(randomized) UNIX domain socket name and blocks after that; for instance:
@example
$ mu scm --listen
/run/user/1000/mu-scm-15269.sock
@end example

You can connect to this with external tools, for instance with @command{socat}:
@example
$ socat - UNIX-CONNECT:/run/user/1000/mu-scm-15269.sock
GNU Guile 3.0.9
Copyright (C) 1995-2023 Free Software Foundation, Inc.

Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This
program is free software, and you are welcome to redistribute it under certain
conditions; type `,show c' for details.

Enter `,help' for help.
scheme@@(guile-user)>
@end example

That is not much of improvement over the normal Guile shell, but you can of
course use more advanced tools; @xref{Hooking up with GNU/Emacs and Geiser}.

@node Hooking up with GNU/Emacs and Geiser
@section Hooking up with GNU/Emacs and Geiser
@cindex GNU/Emacs
@cindex Geiser

Many people like interacting with Guile through Emacs and the ``Geiser''
package, and that is possible with @command{mu scm} as well, using the Unix
domain socket, as discussed in @xref{Listening on a Unix Domain Socket}.

Assuming you have installed the @code{guile-geiser} package (available through
the ELPA package archive), the following snippet makes that easy:
@lisp
(require 'geiser-guile)

(defvar mu-scm-listen-command "mu scm --listen"
  "mu command to start an scm repl listening on a socket.")

(defun mu-scm-geiser-connect ()
  "Start a mu scm repl and connect to it using geiser.
Connect to mu's scm (guile) interface through Geiser."
  (interactive)
  (make-process
   :name "*mu-scm-repl*"
   :command `("sh" "-c"  ,mu-scm-listen-command)
   :filter (lambda (_proc chunk)
             (when (string-match "^\\(mu-scm.*\\.sock\\)$" chunk)
               (geiser-connect-local 'guile (match-string 1 chunk))))))
@end lisp

After evaluating this, you can use @command{M-x mu-scm-geiser-connect} to start
the REPL, with all the Geiser bells & whistles.

@node Hooking up with Mu4e
@section Hooking up with Mu4e
@cindex Mu4e

If you use @code{mu4e}, connecting to the SCM REPL is even easier than with
``plain'' Emacs.

First tell @code{mu4e} to starts it server with with @t{--listen} parameter:
@lisp
(setq mu4e-mu-scm-server t)
@end lisp
After that, (re)start @code{mu4e}.

Now should be able to connect to the REPL using @kbd{M-x mu4e-mu-scm-repl}. Like
@ref{Hooking up with GNU/Emacs and Geiser}, this depends on the
@code{geiser-guile} package.

The SCM instance uses the same database/store instance that @code{mu4e} uses.

@node Shell
@chapter Shell

This chapter discusses the @t{mu-scm}-powered shell.

After installation (@xref{Getting started}), you can start the @t{mu-scm} shell
by issuing:
@example
$ mu scm
@end example

This is the Guile
REPL@footnote{@url{https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop}}
customized for @t{mu}. In particular, it supports all the common @t{mu}
command-line arguments for specifying where your @t{mu} stores its data and so
on (see the @t{mu} and @t{mu scm} man-pages for details).

@example
$ mu scm
[....]
Welcome to the mu shell!

GNU Guile 3.0.9
Copyright (C) 1995-2023 Free Software Foundation, Inc.

Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.

Enter `,help' for help.
scheme@@(guile-user)>
@end example

This shell is set-up for use with @t{mu} with the module imported and the
message database loaded. So we can try some simple queries, using the
@code{mfind} function, which mimics @t{mu find}@footnote{It is called @t{mfind}
instead of @t{find} to avoid clashing with the core Guile function by that
name.}
@example
scheme@@(guile-user)> (mfind "rhinoceros")
$1 = (#<<message> 7f2aa671fce0>)
@end example

Which means we found one message matching @t{rhinoceros}. If you don't have such
a message, try some different query. We can then inspect the message, using the
@t{$1} temporary:

@example
scheme@@(guile-user)> (subject (car $1))
$2 = "Important message about African animals"
@end example

@node Scripts
@chapter Scripts

In the @ref{Shell} chapter, we saw how you can use @t{mu-scm} interactively. In
this also possible to run @emph{scripts}. Generally, you can invoke a script by
passing its name to @command{mu scm}, for example:
@example
mu scm path/to/script/myscript.scm
@end example

@t{mu-scm} expects scripts to have a procedure @code{main} of the form:

@deffn {Scheme Procedure} main script #:rest args
@end deffn

@t{main} receives the script (path) as its first argument, and any other
arguments in the list @t{args}.

Thus, an example script might look like:
@lisp
(use-modules (mu))

(define* (main script #:rest args)
  (format #t "running script ~a and arguments ~s\n" script args)
  (for-each
   (lambda (msg)
     (format #t "~a ~a\n"
             (time->string (date msg))
             (or (subject msg) "No subject")))
   (mfind "hello AND date:2015.." #:max-results 5)))
@end lisp

You can run it like this:
@example
$ mu scm ~/myscript.scm some args 123
running script /home/user/myscript.scm and arguments  ("some" "args" "123")
2015-01-02T12:41:13 Happy 2015! It's Day 2 - How Are Those Resolutions Coming?
2015-01-06T12:29:21 Brunch Sunday 11.1.
2015-01-06T18:05:27 Moderator's spam report for mu-discuss@@googlegroups.com
2015-01-13T11:37:27 Upvoted: The Story Behind the Users Who Make Reddit's Front Page
2015-01-16T17:06:23 [mu] combining maildirs in query (#559)
@end example

Quite likely, your output will differ from the above.

@node API Reference with examples
@chapter API Reference with examples

This chapter goes through the @t{mu-scm} API. For this, we need to understand a
few key concepts, represented in some GOOP objects and other data-structures:

@itemize
@item the @t{<store>} represents the mu database with information about messages
@item from the store, you can find @t{<message>} objects, each of which represent a specific message
(similar to what you get from @code{mu find})
@item the store also exposes tha contacts in the store as alists (``association lists'')
(similar to what you get from @code{mu cfind})
@end itemize

@menu
* Store:: where message information lives
* Message:: inspecting individual messages
* Miscellaneous:: other functions
* Helpers:: some helper functions
@end menu

@node Store
@section Store

The store represents the @t{mu} database, i.e., the place where @t{mu index}
stores information about messages and contacts.

While you could theoretically have @emph{multiple} stores, for now @t{mu-scm}
only supports a @emph{single} one, which is the store you opened when you
started @command{mu scm}.

For completeness and possible future use, store-related methods do take a
@t{store} parameter or a @t{#:store} keyword parameter, but it can be left out
for for now.

Hence, for brevity, in the API descriptions below, the @t{store} parameter is
implicit.

The store currently only exposes a few methods, described below.

@deffn {Scheme Procedure} mfind query [#:related? #f] [#:skip-dups? #f]
       [#:sort-field 'date]
       [#:reverse? #f] [#:max-results #f]
@end deffn

Perform a query for messages in the store, and return a list of message objects
(@xref{Message}) for the matches.

@itemize
@item @var{query} is a Mu query; see the @t{mu-query} man-page for details
@item @var{#:related?} whether @emph{related} messages should be included.
This is similar to the @t{--include-related} parameter for @command{mu find}
@item @var{#:skip-dups?} whether to exclude duplicate messages
This is similar to the @t{--skip-dups} parameter for @command{mu find}
@item @var{#:sort-field} a symbol, the message field to sort by
You can sort by the fields (see @command{mu info fields} that have a @t{value=yes})
@item @var{#:reverse?} whether to reverse the sort-direction (make it descending)
@item @var{#:max-results} the maximum number of results
By default @emph{all} matches are returned
@end itemize

@t{mfind} mimics the @command{mu find} command-line command.

Example usage:
@lisp
(mfind "capybara" #:skip-dups? #t #:sort-field 'subject)
=> (#<<message> 7f3c8ac09c00> #<<message> 7f3c8ac09be0>)
@end lisp

@deffn {Scheme Procedure} cfind pattern [#:personal? #f] [#:after #f] [#:max-results #f]
@end deffn

Search for contacts in the store, and return a list of contacts for the matches.
Each contact is an association list with at least a key (symbol @t{email}) with
e-mail address as its value, and possibly a @t{name} key with the contact's
name. In the future, other fields may be added.

@itemize
@item @var{pattern} is a basic case-insensitive PCRE-compatible regular expression
see the @t{pcre(3)} man-page for details
@item @var{#:personal?} if true, only match @emph{personal} contacts
A personal contact is a contact seen in message where ``you'' were an explicit
sender or recipient, thus excluding mailing-list. Personal addresses are those
that were specified at store creation time - see the @t{mu-init} man-page, in
particular the @t{--personal-address} parameter
@item @var{#:after} only include contacts last-seen after some time-point
Specified as the number of seconds since epoch. Helper-function
@code{iso-date->time-t} can be useful here.
@item @var{#:max-results} (optional) the maximum number of results
By default, @emph{all} matches are returned
@end itemize

@t{cfind} mimics the @command{mu cfind} command-line command.

Example usage:
@lisp
(car (cfind "smith" #:personal? #t))
=> ((name . "Hannibal Smith") (email . "jhs@@example.com"))
@end lisp

@deffn {Scheme Procedure} mcount
@end deffn

Return the number of messages in the store.

Example usage:
@lisp
(mcount)
=> 140728
@end lisp

@deffn {Scheme Procedure} store->alist
@end deffn
Retrieve an association list (``alist'') with information about the store.

Example:
@lisp
(store->alist)
=> ((batch-size . 50000) (created . 1741180008) (max-message-size . 100000000)
     (personal-addresses "djcb@@example.com" "msx@@example.com")
     (root-maildir . "/home/user/Maildir") (schema-version . 500))
@end lisp

More fields may be added.

@deffn {Scheme Procedure} root-maildir
@end deffn

Get the root maildir directory, that is, the root of under the directory under
which all messages reside.

This is equivalent to @code{(assoc-ref (store->alist) 'root-maildir)}.

@deffn {Scheme Procedure} personal-addresses
@end deffn

Get the list of personal-addresses as defined in the @code{mu} database, which
may be empty.

This is equivalent to @code{(or (assoc-ref (store->alist) 'personal-addresses) '())},

Any element in this list is either a plain e-mail address, or a PCRE-compatible
regular expression when the first and last characters are @t{/} (forward-slash);
see @t{pcre(3)} for further details.

@deffn {Scheme Procedure} labels
@end deffn
Get the list of all labels present in the store, which may be empty. Not to be
confused with @code{labels} procedure for a @code{message} object.

@deffn {Scheme Procedure} labels
@end deffn
Get the list of all labels present in the store, which may empty.
Not to be confused with @code{labels} procedure for a @code{message} object.

@node Message
@section Message

A @code{message} object represents the information about an e-mail message.
@t{mu} gets this information either from its database (the @t{mu} store), e.g.,
with @code{mfind} (see @xref{Store}) or by reading an email message from the
file-systems with @code{make-message}.

In many of the examples below we assume there is some @code{message} object,
e.g. as retrieved through:
@lisp
(define msg (car (mfind "hello")))
@end lisp

@anchor{full-message} Many of the procedures below use the internal
representation of the message from the database; this re-uses the same
information that @code{mu4e} uses:

@itemize
@item Basics: @code{subject}, @code{message-id}, @code{priority}
@item Contact fields: @code{from}, @code{to}, @code{cc}, @code{bcc}
@item Dates: @code{date} and @code{last-change}
@item ``Meta-data'' about a message: @code{maildir}, @code{path}, @code{size}, @code{labels}
@item Miscellaneous: @code{flags}, @code{references}, @code{thread-id}, @code{mailing-list}, @code{language}
@end itemize

However, that is not sufficient for all cases: @code{body} and @code{header}
need the full message. The same is true for @code{mime-parts}.

For these methods, @code{mu} needs to open the message file from the
file-system. This is handled transparently inside @t{mu-scm}, except that
full-method-procedures are a bit slower relatively to the database-only ones.

@subsection Basics

@deffn {Scheme Procedure} make-message path
@end deffn
Create a new message object from a file-system path.

This is a @emph{full message}, unlike the ones you get from a store-query (i.e.,
@code{mfind}).

@deffn {Scheme Procedure} subject message
@end deffn
Get the message subject, or @t{#f} if there is none.

For example:
@lisp
(subject msg)
=> "Hello!"
@end lisp

@deffn {Scheme Procedure} maildir message
@end deffn
Get the message subject, or @t{#f} if there is none.

For example:
@lisp
(maildir msg)
=> "/inbox"
@end lisp

@deffn {Scheme Procedure} path message
@end deffn
Get the file-system path for the message.

For example:
@lisp
(path msg)
=> "/home/user/Maildir/archive/cur/1546942532.adb906ab91921e10.hyperion:2,DS"
@end lisp

@deffn {Scheme Procedure} message-id message
@end deffn
Get the message's @t{Message-ID} field, or @t{#f} if there is none.

For example:
@lisp
(message-id msg)
=> "87a15477-dd66-43e5-a722-81c545d6af19@@gmail.com"
@end lisp

@deffn {Scheme Procedure} date message
@end deffn
Get the message's @t{Date} field (the sent-date), or @t{#f} if there is none.
@t{date} expressed the data as the number of seconds since epoch, @t{time_t}.

As a convenience, @t{iso-date} expresses the date as an ISO-8601-compatible
string or an empty string of the same length.

For example:
@lisp
(date msg)
=> 1750064431
(iso-date msg)
=> 2025-06-16T09:00:31
@end lisp

@deffn {Scheme Procedure} body message  [#:html? #f]
@end deffn
Get the message body as a string, or return @code{#f} if not found.

If @var{#:html?} is non-@t{#f}, get the HTML-body instead.

This requires the @ref{full-message,,full message}.

@deffn {Scheme Procedure} message-id message
@end deffn
Get the message's @t{Message-ID} field, or @t{#f} if there is none.

For example:
@lisp
(message-id msg)
=> "87a15477-dd66-43e5-a722-81c545d6af19@@gmail.com"
@end lisp

@subsection MIME-parts

Messages consist of one or more MIME-parts, which include the body, attachments
and other parts. To get the MIME-parts for a message, you can use the
@code{mime-parts} method on a @code{message}.

@deffn {Scheme Procedure} mime-parts message
@end deffn
Get the MIME-parts for this message, as a list of @code{<mime-part>} objects.

A MIME-parts is an object with a few methods.

@deffn {Scheme Procedure} mime-part->alist mime-part
@end deffn
Get an association list (alist) describing the MIME part.

For example:
@lisp
;; describe the second MIME-part of the first message with an attachment
(mime-part->alist
 (cadr (mime-parts
       (car (mfind "flag:attach" #:max-results 1)))))
=> ((filename . "emacs.png") (size . 18188) (content-type . "image/png") (index . 1))
@end lisp

Depending on the MIME-part, different fields can be present:
@itemize
@item @t{index}
the index (number) of the part, 0-based
@item @t{mime-type}
the MIME-type of the part
@item @t{size}
the size of the part in bytes. For encoded parts, this is the @emph{encoded} size
@item @t{filename} the filename (for attachments).
This is as specified in the message, but with forward slashes and
control-characters removed or substituted with @t{-}.
@item @t{signed?}
is this part (cryptographically) signed?
@item @t{encrypted?}
is this part encrypted?
@end itemize

@deffn {Scheme Procedure} make-port mime-part [#:content-only? #f]
                                              [#:decode? #t]
@end deffn
Get a read-port for the given MIME-part. Ports are the standard mechanism for
dealing with I/O in Guile; see its documentation for further details.

If @code{content-only?} is true, only include the contents, not headers. If
@code{decode?} is true, decode the content (from e.g., Base-64); in that
case, @code{content-only?} is implied to be #t.


@deffn {Scheme Procedure} write-to-file [#:filename #f] [#:overwrite? #f]
@end deffn
Write MIME-part to file.

Use @code{filename} is the file/path to use for writing; if this is @code{#f},
the name using the @code{filename} procedure.

If @code{overwrite?} is true, overwrite existing files of the same name;
otherwise, raise an error if the file already exists.


@deffn {Scheme Procedure} filename mime-part
@end deffn
Determine a filename for the given MIME-part.

This is either taken from the @t{filename} property of the MIME-part alist, or,
If that does not exist, a generic name.


@subsection Contacts

Message fields @t{To:}, @t{From:}, @t{Cc:} and @t{Bcc:} contain @emph{contacts}.
@t{mu-scm} represents those as list of contact-alists, or contacts for short.
Each contact is an alist with at least an @code{email} and optionally a
@code{name} field. For instance:
@lisp
(to msg)
=> (((name . "Hannibal Smith") (email . "jhs@@example.com"))
    ((email . "murdock@@example.com")))
@end lisp

@deffn {Scheme Procedure} from message
@end deffn
Get the list of message senders (usually a single one).

@deffn {Scheme Procedure} to message
@end deffn
Get the message's intended @t{To:} recipients list.

@deffn {Scheme Procedure} cc message
@end deffn
Get the message's intended carbon-copy @t{Cc:} recipients list.

@deffn {Scheme Procedure} bcc message
@end deffn
Get the message's intended blind carbon-copy @t{Bcc:} recipients list.

@subsection Flags

Message can have a number of properties or @emph{flags}.

@deffn {Scheme Procedure} flags message
@end deffn
Get the message's list of @emph{flags}. Flags are symbols, see @command{mu info
fields} for the list of all flags.

For example:
@lisp
(flags msg)
=> (draft seen personal)
@end lisp

There are some helpers to check for the presence of specific flags:

@deffn {Scheme Procedure} flag? message flag
@end deffn
Does the message have the given flag? @t{#t} or @t{#f}.

For example:
@lisp
(flags? msg 'personal)
=> #t
(flags? msg 'calendar)
=> #f
@end lisp

@deffn {Scheme Procedure} draft? message
@end deffn
Does the message have the @t{draft} flag? Returns @t{#t} or @t{#f}.

@deffn {Scheme Procedure} flagged? message
@end deffn
Does the message have the @t{flagged} flag? Returns @t{#t} or @t{#f}.

@deffn {Scheme Procedure} passed? message
@end deffn
Does the message have the @t{passed} flag? I.e., has it been forwarded?
Returns @t{#t} or @t{#f}.

@deffn {Scheme Procedure} replied? message
@end deffn
Does the message have the @t{replied} flag? Returns @t{#t} or @t{#f}.

@deffn {Scheme Procedure} seen? message
@end deffn
Does the message have the @t{seen} flag? Returns @t{#t} or @t{#f}.

@deffn {Scheme Procedure} trashed? message
@end deffn
Does the message have the @t{trashed} flag? I.e., has it been marked for
removal? Returns @t{#t} or @t{#f}.

@deffn {Scheme Procedure} new? message
@end deffn
Is this a new message? Returns @t{#t} or @t{#f}.

@deffn {Scheme Procedure} signed? message
@end deffn
Is this a cryptographically signed message? Returns @t{#t} or @t{#f}.

@deffn {Scheme Procedure} encrypted? message
@end deffn
Is this an encrypted message? Returns @t{#t} or @t{#f}.

@deffn {Scheme Procedure} attach? message
@end deffn
Does the message have an attachment? Returns @t{#t} or @t{#f}.

@deffn {Scheme Procedure} unread? message
@end deffn
Is this message unread? I.e., either new or not seen? Returns @t{#t} or @t{#f}.

@deffn {Scheme Procedure} list? message
@end deffn
Is this a mailing-list message? Returns @t{#t} or @t{#f}.

@deffn {Scheme Procedure} personal? message
@end deffn
Is this a personal message? Returns @t{#t} or @t{#f}.

@deffn {Scheme Procedure} calendar? message
@end deffn
Does this message include a calendar invitation? Returns @t{#t} or @code{#f}.

@subsection Miscellaneous

@deffn {Scheme Procedure} changed message
@end deffn
Get the time of the message's last change (through @t{mu}), or @code{#f} if there
is none. The time is expressed the data as the number of seconds since epoch,
@t{time_t}.

For example:
@lisp
(last-change msg)
=> 1703336567
@end lisp

@deffn {Scheme Procedure} priority message
@end deffn
Get the message's priority. This is a symbol, either @t{high}, @t{normal} or
@t{low}, or @code{#f} if not present.

For example:
@lisp
(priority msg)
=> normal
@end lisp

@deffn {Scheme Procedure} size message
@end deffn
Get the message's size in bytes.

For example:
@lisp
(size msg)
=> 2815
@end lisp

@deffn {Scheme Procedure} labels message
@end deffn
Get the list of labels for this message. Not to be confused with the
@code{labels} procedure for a store.

For example:
@lisp
(labels msg)
=> ("foo" "bar")
@end lisp

@deffn {Scheme Procedure} language message
@end deffn
Get the ISO-639-1 language code for message's primary language or @code{#f} if not
found. This is available only if @t{mu} was built with CLD2 support, see
@command{mu info}. The language code is represented as a symbol, such as @t{en},
@t{nl} or @t{fi}.

For example:
@lisp
(language msg)
=> en
@end lisp

@deffn {Scheme Procedure} header message
@end deffn
Get some arbitrary, raw header from the message.

The @var{header} parameter is a case-insensitive string @emph{without} the colon
(@t{:}).

This requires the @ref{full-message,,full message}.

For example:
@lisp
(header msg "subject")
=> "Re: Musical chairs"
(header msg "From")
=> "\"Raul Endymion\" <raul@@example.com>"
(header msg "Something")
=> #f
@end lisp

@deffn {Scheme Procedure} references message
@end deffn
Get the list of references (message-ids of related messages) for this message.
This combines the @t{References} and @t{In-Reply-To} fields, from oldest to the
immediate parent. Returns @code{#f} if there are no references.

For example:
@lisp
(references msg)
=> ("439C1136.90504@@euler.org" "4399DD94.5070309@@euler.org"
    "20051209233303.GA13812@@gauss.org" "439B41ED.2080402@@euler.org"
    439A1E03.3090604@@euler.org" "20051211184308.GB13513@@gauss.org")
@end lisp

@deffn {Scheme Procedure} thread-id message
@end deffn
Get the oldest reference for the message or its message-id if there is none.
This is useful to identify the thread some message lives in.

For example:
@lisp
(thread-id msg)
=> "439C1136.90504@@euler.org"
@end lisp

For example:
@lisp
(references msg)
=> ("439C1136.90504@@euler.org" "4399DD94.5070309@@euler.org"
    "20051209233303.GA13812@@gauss.org" "439B41ED.2080402@@euler.org"
    439A1E03.3090604@@euler.org" "20051211184308.GB13513@@gauss.org")
@end lisp

@deffn {Scheme Procedure} mailing-list message
@end deffn
Get the mailing-list id for this message (corresponding with the @t{List-Id:}
field), or @code{#f} if there is none.

For example:
@lisp
(mailing-list msg)
=> "gnu-emacs-sources.gnu.org"
@end lisp


@c @deffn {Scheme Procedure} sexp message
@c @end deffn
@c Get the message's s-expression.

@c @t{mu} caches an s-expression for each message; this was designed as an
@c optimization for @code{mu4e}, but @t{mu-scm} uses it as well. The details of this
@c s-expression (a property-list) are internal to @t{mu} (so do not base your next
@c billion-dollar startup on it), but it can be useful for development and
@c debugging.

@node Miscellaneous
@section Miscellaneous

@defvar %options
@end defvar

An association-list (alist) of general options passed to @command{mu scm} or
their default values.
@lisp
 %options
=> ((mu-home . #f) (quiet . #f) (debug . #f) (verbose . #f))
@end lisp

@c @defvar %preferences
@c @end defvar

@c An association list (alist) of user-preferences that influence interactive use.
@c E.g., the way how certain things are displayed. The alist maps symbols to values:
@c @itemize
@c @item @code{short-date}
@c a @code{strftime}-compatible string for the display format of short dates.
@c @item @code{utc?}
@c boolean, whether to assume UTC for dates/times, such as for @code{string->time} and @code{time->string}
@c @end itemize

@c @lisp
@c %preferences
@c  ((short-date-format . "%F %T") (input-utc? . #f) (output-utc? . #f))
@c @end lisp

@node Helpers
@section Helpers

@deffn {Scheme Procedure} debug frm . args
@end deffn

@deffn {Scheme Procedure} info frm . args
@end deffn

@deffn {Scheme Procedure} warning frm . args
@end deffn

@deffn {Scheme Procedure} critical frm . args
@end deffn

Log using @t{mu}'s logging facilities at the given level (debug, info, warning
or critical). @code{frm} and @code{args} are expected to be a format string and
its arguments, respectively, according to Guile's @code{format} function.

Note: where the log output exactly appears (i.e., log-file, journal, console,
nowhere) dependis on the particulars of the system and how mu was started; see
the @t{mu (1)} man-page for details on the latter.

@deffn {Scheme Procedure} string->time timestr [#:utc? (assoc-ref %preferences 'utc?)]
@end deffn
Convert some ISO-8601-style time-string to a seconds-since-epoch @t{time_t}
value. @var{timestr} is expected to be in the @t{strftime}-format @t{%F%T}, or a
prefix thereof. Non-numerical characters are ignored.

You can influence whether UTC is assumed using the optional @code{#:utc?}
parameter. The input time/date format is fixed.
@c which uses @code{%preferences} for its default.

@deffn {Scheme Procedure} time->string
                       [#:format (assoc-ref %preferences 'short-date)]
                       [#:utc? (assoc-ref %preferences 'utc?)]
@end deffn
Convert a @t{time_t} value (``seconds-since-epoch'') to a string. The optional
@code{#:format} parameter (an @code{strftime}-compatible string) determines the
output format, while the @code{#:utc?} determines whether to use UTC.
@c Defaults are determined by the @code{%preferences} variable.

If @var{time_t} is @code{#f}, return @code{#f}.

@node GNU Free Documentation License
@appendix GNU Free Documentation License

@include fdl.texi

@page
@node Procedure Index
@unnumbered Procedure Index

This is an alphabetical list of all the public procedures and macros in @t{mu-scm}.

@printindex fn

@page
@node Variable Index
@unnumbered Variables Index

This is an alphabetical list of all the public variables @t{mu-scm}.

@printindex vr

@bye
