This is mu-guile.info, produced by makeinfo version 7.1 from
mu-guile.texi.

Copyright © 2012-2024 Dirk-Jan C. Binnema

     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."
INFO-DIR-SECTION The Algorithmic Language Scheme
START-INFO-DIR-ENTRY
* Mu-guile: (mu-guile).        Guile-bindings for the mu e-mail indexer/searcher
END-INFO-DIR-ENTRY


File: mu-guile.info,  Node: Top,  Next: Getting started,  Up: (dir)

mu-guile manual
***************

Welcome to mu-guile!

   mu is a program for indexing and searching your e-mails.  It can
search your messages in many different ways, but sometimes that may not
be enough.  If you have very specific queries, or want do generate some
statistics, you need some more power.

   mu-guile is made for those cases.  mu-guile exposes the internals of
mu and its database to the guile programming language.  Guile is the
_GNU Ubiquitous Intelligent Language for Extensions_ - a version of the
_Scheme_ programming language and the official GNU extension language.

   Guile/Scheme is a member of the _Lisp_ family of programming
languages - like emacs-lisp, _Racket_, Common Lisp.  If you're not
familiar with Scheme, mu-guile is an excellent opportunity to learn a
bit about!

   Trust me, it's not very hard - and it's _fun_!

* Menu:

* Getting started::
* Initializing mu-guile::
* Messages::
* Contacts::
* Attachments and other parts::
* Statistics::
* Plotting data::
* Writing scripts::

Appendices

* Recipes:: Snippets do specific things
* GNU Free Documentation License::  The license of this manual.


File: mu-guile.info,  Node: Getting started,  Next: Initializing mu-guile,  Prev: Top,  Up: Top

1 Getting started
*****************

* Menu:

* Installation::
* Making sure it works::

This chapter walks you through the installation and the basic setup.


File: mu-guile.info,  Node: Installation,  Next: Making sure it works,  Up: Getting started

1.1 Installation
================

mu-guile is part of mu - by installing the latter, the former is
necessarily installed as well.  At the time of writing, there are no
distribution-provided packaged versions of mu-guile; so for now, you
need to follow the steps below.

1.1.1 Guile 2.x
---------------

mu-guile is built automatically when mu is built, if you have guile
version 2 or higher.  (mu checks for this during configure).  Thus, the
first step is to ensure you have guile installed.

   On Debian/Ubuntu you can install guile 2.x using the guile-2.0-dev
package (and its dependencies):
     $ sudo apt-get install guile-2.0-dev

   At the time of writing, there are no official packages for Fedora(1).
If you are using Fedora or any other system that does not have packages,
you need to compile guile from source(2).

1.1.2 gnuplot
-------------

For creating graphs with mu-guile, you need the gnuplot program - most
likely, there is a package available for your system; for example:

     $ sudo apt-get install gnuplot

   and in Fedora:

     $ sudo yum install gnuplot

1.1.3 mu
--------

Assuming guile 2.x is installed correctly, mu finds it during its
configure-stage, and creates mu-guile.  Building mu follows the normal
steps - please see the mu documentation for the details.

   The output of ./configure should end with a little text describing
the detected versions of various libraries mu depends on.  In
particular, it should mention the guile version, e.g.

     Guile version                        : 2.0.3.82-a2c66

   If you don't see any line referring to guile, please install it, and
run configure again.  After a successful ./configure, we can make and
install the package:

     $ make && sudo make install

1.1.4 mu-guile
--------------

After this, mu and mu-guile are installed - usually somewhere under
/usr/local.You may need to update guile's ‘%load-path’ to find it there.
You can check the current ‘%load-path’ with the following:

     guile -c '(display %load-path)(newline)'

   If necessary, you can add the %load-path by adding to your
‘~/.guile’:

     (set! %load-path (cons "/usr/local/share/guile/site/2.0" %load-path))

   Or, alternatively, you can set GUILE_LOAD_PATH:
     export GUILE_LOAD_PATH=/usr/local/share/guile/site/2.0

   In both cases the directory should be the directory that contains the
installed mu.scm; if you installed mu under a different prefix, you must
change the ‘%load-path’ accordingly.  After this, you should be ready to
go!

   Furthermore, you need to ensure that guile can find the mu-guile
library; for this we can use ‘LTDL_LIBRARY_PATH’, e.g.
     export LTDL_LIBRARY_PATH=/usr/local/lib

   ---------- Footnotes ----------

   (1) <https://bugzilla.redhat.com/show_bug.cgi?id=678238>

   (2) 
<http://www.gnu.org/software/guile/manual/html_node/Obtaining-and-Installing-Guile.html#Obtaining-and-Installing-Guile>


File: mu-guile.info,  Node: Making sure it works,  Prev: Installation,  Up: Getting started

1.2 Making sure it works
========================

Assuming mu-guile has been installed correctly (*note Installation::),
and also assuming that you have already indexed your e-mail messages (if
necessary, see the mu-index man-page), we are ready to start mu-guile; a
session may look something like this:

GNU Guile 2.0.5.123-4bd53
Copyright (C) 1995-2012 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)>

Now, copy-paste the following after the prompt:

     (use-modules (mu))
     (mu:initialize)
     (for-each
         (lambda(msg)
            (format #t "Subject: ~a\n" (mu:subject msg)))
             (mu:message-list "hello"))

After pressing <Enter>, you should get a list of all subjects of
messages that match hello:

...
Subject: RE: The Bird Serpent War Cataclysm
Subject: Hello!
Subject: Re: post-run tomorrow
Subject: When all is lost
...

If all this works, congratulations!  mu-guile is installed now, ready to
serve your every searching need!


File: mu-guile.info,  Node: Initializing mu-guile,  Next: Messages,  Prev: Getting started,  Up: Top

2 Initializing mu-guile
***********************

We now have installed mu-guile, and in *note Making sure it works::
confirmed that things work by trying some simple script.  In this and
the following chapters, we take a closer look at programming with
mu-guile.

   It is possible to write separate programs with mu-guile, but for now
we'll do things _interactively_, that is, from the Guile-prompt
("REPL").

   As we have seen, we start our mu-guile session by starting guile:

$ guile

GNU Guile 2.0.5.123-4bd53
Copyright (C) 1995-2012 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)>

   The first thing we need to do is loading the modules.  All the basics
are in the (mu) module, with some statistical extras in (mu stats), and
some graph plotting functionality in (mu plot)(1).  Let's load all of
them:
scheme@(guile-user)> (use-modules (mu) (mu stats) (mu plot))

   The first time you do this, guile will probably respond by showing
some messages about compiling the modules, and then return to you with
another prompt.  Before we can do anything with mu guile, we need to
initialize the system:

scheme@(guile-user)> (mu:initialize)

   This opens the database for reading, using the default location of
‘~/.cache/mu’(2)

   Now, mu-guile is ready to go.  In the next chapter, we go through the
modules and show what you can do with them.

   ---------- Footnotes ----------

   (1) ‘(mu plot)’ requires the gnuplot program

   (2) If you keep your mu database in a non-standard place, use
‘(mu:initialize "/path/to/my/mu/")’


File: mu-guile.info,  Node: Messages,  Next: Contacts,  Prev: Initializing mu-guile,  Up: Top

3 Messages
**********

In this chapter, we discuss searching messages and doing things with
them.

* Menu:

* Finding messages:: query for messages in the database
* Message methods::  what methods are available for messages?
* Example - the longest subject:: find the messages with the longest subject


File: mu-guile.info,  Node: Finding messages,  Next: Message methods,  Up: Messages

3.1 Finding messages
====================

Now we are ready to retrieve some messages from the system.  There are
two main procedures to do this:

   • ‘(mu:message-list [<search-expression>])’
   • ‘(mu:for-each-message <procedure> [<search-expression>])’

The first procedure, ‘mu:message-list’ returns a list of all messages
matching <search-expression>; if you leave <search-expression> out, it
returns _all_ messages.  For example, to get all messages with coffee in
the subject line:

scheme@(guile-user)> (mu:message-list "subject:coffee")
$1 = (#<<mu:message> 9040640> #<<mu:message> 9040630>
      #<<mu:message> 9040570>)

Apparently, we have three messages matching subject:coffee, so we get a
list of three ‘<mu:message>’ objects.  Let's just use the ‘mu:subject’
procedure ('method') provided by ‘<mu:message>’ objects to retrieve the
subject-field (more about methods in the next section).

   For your convenience, guile has saved the result of our last query in
a variable called $1, so to get the subject of the first message in the
list, we can do:

scheme@(guile-user)> (mu:subject (car $1))
$2 = "Re: best coffee ever!"

The second procedure we mentioned, ‘mu:for-each-message’, executes some
procedure for each message matched by the search expression (or _all_
messages if the search expression is omitted):

scheme@(guile-user)> (mu:for-each-message
                       (lambda(msg)
                         (display (mu:subject msg))
                         (newline))
                      "subject:coffee")
Re: best coffee ever!
best coffee ever!
Coffee beans
scheme@(guile-user)>

Using ‘mu:message-list’ and/or ‘mu:for-each-message’(1) and a couple of
<mu:message> methods, together with what Guile/Scheme provides, should
allow for many interesting programs.

   ---------- Footnotes ----------

   (1) Implementation node: ‘mu:message-list’ is implemented in terms of
‘mu:for-each-message’, not the other way around.  Due to the way mu
works, ‘mu:for-each-message’ is rather more efficient than a combination
of ‘for-each’ and ‘mu:message-list’


File: mu-guile.info,  Node: Message methods,  Next: Example - the longest subject,  Prev: Finding messages,  Up: Messages

3.2 Message methods
===================

Now that we've seen how to retrieve lists of message objects
(‘<mu:message>’), let's see what we can do with such an object.

   ‘<mu:message>’ defines the following methods that all take a single
‘<mu:message>’ object as a parameter.  We won't go into the exact
meanings for all of these procedures here - for the details about
various flags / properties, please refer to the mu-find man-page.

   • ‘(mu:bcc msg)’: the Bcc field of the message, or #f if there is
     none
   • ‘(mu:body-html msg)’: : the html body of the message, or #f if
     there is none
   • ‘(mu:body-txt msg)’: the plain-text body of the message, or #f if
     there is none
   • ‘(mu:cc msg)’: the Bcc field of the message, or #f if there is none
   • ‘(mu:date msg)’: the Date field of the message, or 0 if there is
     none
   • ‘(mu:flags msg)’: list of message-flags for this message
   • ‘(mu:from msg)’: the From field of the message, or #f if there is
     none
   • ‘(mu:maildir msg)’: the maildir this message lives in, or #f if
     there is none
   • ‘(mu:message-id msg)’: the Message-Id field of the message, or #f
     if there is none
   • ‘(mu:path msg)’: the file system path for this message
   • ‘(mu:priority msg)’: the priority of this message (either
     mu:prio:low, mu:prio:normal or mu:prio:high
   • ‘(mu:references msg)’: the list of messages (message-ids) this
     message refers to in(mu: the References: header
   • ‘(mu:size msg)’: size of the message in bytes
   • ‘(mu:subject msg)’: the Subject field of the message, or #f if
     there is none.
   • ‘(mu:tags msg)’: list of tags for this message
   • ‘(mu:timestamp msg)’: the timestamp (mtime) of the message file, or
     #f if there is none.  message file
   • ‘(mu:to msg)’: the sender of the message, or #f if there is none

   With these methods, we can query messages for their properties; for
example:

scheme@(guile-user)> (define msg (car (mu:message-list "snow")))
scheme@(guile-user)> (mu:subject msg)
$1 = "Re: Running in the snow is beautiful"
scheme@(guile-user)> (mu:flags msg)
$2 = (mu:flag:replied mu:flag:seen)
scheme@(guile-user)> (strftime "%F" (localtime (mu:date msg)))
$3 = "2011-01-15"

   There are a couple more methods:
   • ‘(mu:header msg "<header-name>")’ returns an arbitrary message
     header (or #f if not found) - e.g.  ‘(header msg "User-Agent")’
   • If you include the mu contact module, the ‘(mu:contacts msg
     [contact-type])’ method (to get a list of contacts) is added.
     *Note Contacts::.
   • If you include the mu part module, the ‘((mu:parts msg)’ and
     ‘(mu:attachments msg)’ methods are added.  *Note Attachments and
     other parts::.


File: mu-guile.info,  Node: Example - the longest subject,  Prev: Message methods,  Up: Messages

3.3 Example - the longest subject
=================================

Now, let's write a little example - let's find out what is the _longest
subject_ of any e-mail messages we received in the year 2011.  You can
try this if you put the following in a separate file, make it
executable, and run it like any program.

     #!/bin/sh
     exec guile -s $0 $ !#

     (use-modules (mu))
     (use-modules (srfi srfi-1))

     (mu:initialize)

     ;; note: (subject msg) => #f if there is no subject
     (define list-of-subjects
       (map (lambda (msg)
           (or (mu:subject msg) "")) (mu:message-list "date:2011..2011")))
     ;; see the mu-find manpage for the date syntax

     (define longest-subject
       (fold (lambda (subj1 subj2)
           (if (> (string-length subj1) (string-length subj2))
     	subj1 subj2))
         "" list-of-subjects))

     (format #t "Longest subject: ~s\n" longest-subject)

   There are many other ways to solve the same problem, for example by
using an iterative approach with ‘mu:for-each-message’, but it should
show how one can easily write little programs to answer specific
questions about your e-mail corpus.


File: mu-guile.info,  Node: Contacts,  Next: Attachments and other parts,  Prev: Messages,  Up: Top

4 Contacts
**********

We can retrieve the sender and recipients of an e-mail message using
methods like ‘mu:from’, ‘mu:to’ etc.; *Note Message methods::.  These
procedures return the list of recipients as a single string; however,
often it is more useful to deal with recipients as separate objects.

* Menu:

* Contact procedures and objects::
* All contacts::
* Utility procedures::
* Example - mutt export::


File: mu-guile.info,  Node: Contact procedures and objects,  Next: All contacts,  Up: Contacts

4.1 Contact procedures and objects
==================================

Message objects (*note Messages::) have a method mu:contacts:

   ‘(mu:contacts <message-object> [<contact-type>])’

   The <contact-type> is a symbol, one of ‘mu:to’, ‘mu:from’, ‘mu:cc’ or
‘mu:bcc’.  This will then get the contact objects for the contacts of
the corresponding type.  If you leave out the contact-type (or specify
#t for it, you will get a list of _all_ contact objects for the message.

   A contact object (‘<mu:contact>’) has two methods:
   • ‘mu:name’ returns the name of the contact, or #f if there is none
   • ‘mu:email’ returns the e-mail address of the contact, or #f if
     there is none

   Let's get a list of all names and e-mail addresses in the 'To:'
field, of messages matching 'book':

     (use-modules (mu))
     (mu:initialize)
     (mu:for-each-message
        (lambda (msg)
           (for-each
             (lambda (contact)
                (format #t "~a => ~a\n"
                  (or (mu:email contact) "") (or (mu:name contact) "no-name")))
             (mu:contacts msg mu:contact:to)))
         "book")

   This shows what the methods do, but for many uses, it would be more
useful to have each of the contacts only show up _once_ - for that,
please refer to *Note All contacts::.


File: mu-guile.info,  Node: All contacts,  Next: Utility procedures,  Prev: Contact procedures and objects,  Up: Contacts

4.2 All contacts
================

Sometimes you may want to inspect _all_ the different contacts in the mu
database.  This is useful, for instance, when exporting contacts to some
external format that can then be important in an e-mail program.

   To enable this, there is the procedure ‘mu:for-each-contact’, defined
as

   ‘(mu:for-each-contact procedure [search-expression])’.

   This will aggregate the unique contacts from _all_ messages matching
<search-expression> (when it is left empty, it will match all messages
in the database), and execute procedure for each of them.

   The procedure receives an object of the type <mu:contact-with-stats>,
which is a _subclass_ of the <mu:contact> class discussed in *Note
Contact procedures and objects::.  <mu:contact-with-stats> objects
expose the following additional methods:

   • ‘(mu:frequency <contact>)’: returns the _number of times_ this
     contact occurred in one of the address fields
   • ‘(mu:last-seen <contact>)’: returns the _most recent time_ the
     contact was seen in one of the address fields, as a time_t value

   The method assumes an e-mail address is unique for a certain contact;
if a certain e-mail address occurs with different names, it uses the
most recent non-empty name.


File: mu-guile.info,  Node: Utility procedures,  Next: Example - mutt export,  Prev: All contacts,  Up: Contacts

4.3 Utility procedures
======================

To make dealing with contacts even easier, there are a number of utility
procedures that can save you a bit of typing.

   For converting contacts to some textual form, there is
‘(mu:contact->string <mu:contact> format)’, which takes a contact and
returns a text string with the given format.  Currently supported
formats are "org-contact, "mutt-alias", "mutt-ab", "wanderlust" and
"plain".


File: mu-guile.info,  Node: Example - mutt export,  Prev: Utility procedures,  Up: Contacts

4.4 Example - mutt export
=========================

Let's see how we could export the addresses in the mu database to the
addressbook format of the venerable mutt(1) e-mail client.

   The addressbook format that mutt uses is a sequence of lines that
look something like:
alias <nick> [<name>] "<" <email> ">"

   mu guile provides the procedure ‘(mu:contact->string <mu:contact>
format)’ that we can use to do the conversion.

   We may want to focus on people with whom we have frequent
correspondence; so we may want to limit ourselves to people we have seen
at least 10 times in the last year.

   It is a bit hard to _guess_ the nick name for e-mail contacts, but
‘mu:contact->string’ tries something based on the name.  You can always
adjust them later by hand, obviously.

     #!/bin/sh
     exec guile -s $0 $ !#

     (use-modules (mu))
     (mu:initialize)

     ;; Get a list of contacts that were seen at least 20 times since 2010
     (define (selected-contacts)
       (let  ((addrs '())
     	  (start (car (mktime (car (strptime "%F" "2010-01-01")))))
     	  (minfreq 20))
         (mu:for-each-contact
           (lambda (contact)
     	(if (and (mu:email contact)
     	      (>= (mu:frequency contact) minfreq)
     	      (>= (mu:last-seen contact) start))
     	  (set! addrs (cons contact addrs)))))
           addrs))

     (for-each
       (lambda (contact)
         (format #t "~a\n" (mu:contact->string contact "mutt-alias")))
       (selected-contacts))

   This simple program could be improved in many ways; this is left as
an exercise to the reader.

   ---------- Footnotes ----------

   (1) <http://www.mutt.org/>


File: mu-guile.info,  Node: Attachments and other parts,  Next: Statistics,  Prev: Contacts,  Up: Top

5 Attachments and other parts
*****************************

To deal with _attachments_, or, more in general _MIME-parts_, there is
the mu part module.

* Menu:

* Parts and their methods::
* Attachment example::


File: mu-guile.info,  Node: Parts and their methods,  Next: Attachment example,  Up: Attachments and other parts

5.1 Parts and their methods
===========================

The module defines the ‘<mu-part>’ class, and adds two methods to
‘<mu:message>’ objects:
   • ‘(mu:parts msg)’ - returns a list ‘<mu-part>’ objects, one for each
     MIME-parts in the message.
   • ‘(mu:attachments msg)’ - like ‘parts’, but only list those
     MIME-parts that look like proper attachments.

   A ‘<mu:part>’ object exposes a few methods to get information about
the part:
   • ‘(mu:name <part>)’ - returns the file name of the mime-part, or
     ‘#f’ if there is none.
   • ‘(mu:mime-type <part>)’ - returns the mime-type of the mime-part,
     or ‘#f’ if there is none.
   • ‘(mu:size <part>)’ - returns the size in bytes of the mime-part


File: mu-guile.info,  Node: Attachment example,  Prev: Parts and their methods,  Up: Attachments and other parts

5.2 Attachment example
======================

Let's look at some small example.  Let's get a list of the biggest
attachments in messages about Luxemburg:

     #!/bin/sh
     exec guile -s $0 $ !#

     (use-modules (mu))
     (mu:initialize)

     (define (all-attachments expr)
       "Return a list of (name . size) for all attachments in messages
     matching EXPR."
       (let ((pairs '()))
         (mu:for-each-message
           (lambda (msg)
     	(for-each
     	  (lambda (att) ;; add (filename . size) to the list
     	    (set! pairs (cons (cons (mu:name att) (or (mu:size att) 0)) pairs)))
     	  (mu:attachments msg)))
           expr)
         pairs))

     (for-each
       (lambda (att)
         (format #t "~a: ~,1fKb\n"
           (car att) (exact->inexact (/ (cdr att) 1024))))
       (sort (all-attachments "Luxemburg")
         (lambda (att1 att2)
           (< (cdr att1) (cdr att2)))))

   As an exercise for the reader, you might want to re-rewrite the
‘all-attachments’ in terms of ‘mu:message-list’, which would probably be
a bit more elegant.


File: mu-guile.info,  Node: Statistics,  Next: Plotting data,  Prev: Attachments and other parts,  Up: Top

6 Statistics
************

mu-guile offers some convenience procedures to determine various
statistics about the messages in the database.

* Menu:

* Basics:: ‘mu:count’, ‘mu:average’, ...
* Tabulating values:: ‘mu:tabulate’
* Most frequent values:: ‘mu:top-n-most-frequent’


File: mu-guile.info,  Node: Basics,  Next: Tabulating values,  Up: Statistics

6.1 Basics
==========

Let's look at some of the basic statistical operations available, in an
interactive session:
     GNU Guile 2.0.5.123-4bd53
     Copyright (C) 1995-2012 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)> ;; load modules, initialize mu
     scheme@(guile-user)> (use-modules (mu) (mu stats))
     scheme@(guile-user)> (mu:initialize)
     scheme@(guile-user)>
     scheme@(guile-user)> ;; count the number of messages with 'hello' in their subject
     scheme@(guile-user)> (mu:count "subject:hello")
     $1 = 162
     scheme@(guile-user)> ;; average the size of messages with hello in their subject
     scheme@(guile-user)> (mu:average mu:size "subject:hello")
     $2 = 34597733/81
     scheme@(guile-user)> (exact->inexact $2)
     $3 = 427132.506172839
     scheme@(guile-user)> ;; calculate the correlation between message size and
     scheme@(guile-user)> ;; subject length
     scheme@(guile-user)> (mu:correl mu:size (lambda (msg)
                             (string-length (mu:subject msg))) "subject:hello")
     $5 = -0.10804368622292
     scheme@(guile-user)>


File: mu-guile.info,  Node: Tabulating values,  Next: Most frequent values,  Prev: Basics,  Up: Statistics

6.2 Tabulating values
=====================

‘(mu:tabulate <procedure> [<search-expr>])’ applies <procedure> to each
message matching <search-expr> (leave empty to match _all_ messages),
and returns a associative list (a list of pairs) with each of the
different results of <procedure> and their frequencies.  For fields that
contain lists of values (such as address-fields), each of the values in
the list is added separately.

6.2.1 Example: messages per weekday
-----------------------------------

We demonstrate ‘mu:tabulate’ with an example.  Suppose we want to know
how many messages we receive per weekday:

     #!/bin/sh
     exec guile -s $0 $ !#

     (use-modules (mu) (mu stats) (mu plot))
     (mu:initialize)

     ;; create a list like (("Sun" . 13) ("Mon" . 23) ...)
     (define weekday-table
       (mu:weekday-numbers->names
         (sort
           (mu:tabulate
     	(lambda (msg)
     	  (tm:wday (localtime (mu:date msg)))))
           (lambda (a b) (< (car a) (car b))))))

     (for-each
       (lambda (elm)
         (format #t "~a: ~a\n" (car elm) (cdr elm)))
       weekday-table)

   The procedure ‘weekday-table’ uses ‘mu:tabulate-message’ to get the
frequencies per hour - this returns a list of pairs:
((5 . 2339) (0 . 2278) (4 . 2800) (2 . 3184) (6 . 1856) (3 . 2833) (1 . 2993))

   We sort these pairs by the day number, and then apply
‘mu:weekday-numbers->names’, which takes the list, and returns a list
where the day numbers are replace by there abbreviated name (in the
current locale).  Note, there is also ‘mu:month-numbers->names’.

   The script then outputs these numbers in the following form:

Sun: 2278
Mon: 2993
Tue: 3184
Wed: 2833
Thu: 2800
Fri: 2339
Sat: 1856

   Clearly, Saturday is a slow day for e-mail...


File: mu-guile.info,  Node: Most frequent values,  Prev: Tabulating values,  Up: Statistics

6.3 Most frequent values
========================

In the above example, the number of values is small (the seven
weekdays); however, in many cases there can be many different values
(for example, all different message subjects), many of which may not be
very interesting - all we need to know is the top-10 of most frequently
seen values.

   This is fairly easy to achieve using ‘mu:tabulate’ - to get the
top-10 subjects(1), we can use something like this:
     (take
       (sort
         (mu:tabulate mu:subject)
         (lambda (a b) (> (cdr a) (cdr b))))
       10)

   If this is not short enough, mu-guile offers a convenience procedure
to do this: ‘mu:top-n-most-frequent’.  For example, to get the top-10
people we sent mail to most often:

     (mu:top-n-most-frequent mu:to 10 "maildir:/sent")

   Can't make it much easier than that!

   ---------- Footnotes ----------

   (1) this requires the ‘(srfi srfi-1)’-module


File: mu-guile.info,  Node: Plotting data,  Next: Writing scripts,  Prev: Statistics,  Up: Top

7 Plotting data
***************

You can plot the results in the format produced by ‘mu:tabulate’ with
the (mu plot) module, an experimental module that requires the
gnuplot(1) program to be installed on your system.

   The ‘mu:plot-histogram’ procedure takes the following arguments:

   ‘(mu:plot-histogram <data> <title> <x-label> <y-label>
[<want-ascii>])’

   Here, ‘<data>’ is a table of data in the format that ‘mu:tabulate’
produces.  ‘<title>’, ‘<x-label>’ and ‘<y-lablel>’ are, respectively,
the title of the graph, and the labels for X- and Y-axis.  Finally, if
you pass #t for the final ‘<want-ascii>’ parameter, a plain-text
rendering of the graph will be produced; otherwise, a graphical window
will be shown.

   An example should clarify how this works in practice; let's plot the
number of message per hour:

     #!/bin/sh
     exec guile -s $0 $ !#

     (use-modules (mu) (mu stats) (mu plot))
     (mu:initialize)

     (define (mail-per-hour-table)
       (sort
         (mu:tabulate
           (lambda (msg)
     	(tm:hour (localtime (mu:date msg)))))
         (lambda (x y) (< (car x) (car y)))))

     (mu:plot-histogram (mail-per-hour-table) "Mail per hour" "Hour" "Frequency")

				 Mail per hour
Frequency
  1200 ++--+--+--+--+-+--+--+--+--+-+--+--+--+-+--+--+--+--+-+--+--+--+--++
       |+  +  +	 +  + +	 + "/tmp/fileHz7D2u" using 2:xticlabels(1) ********
  1100 ++							     *** +*
       ****							     * *  *
  1000 *+ *							  **** * +*
       *  *			      ******  ****		  * ** *  *
   900 *+ *			      * ** ****	 *	       **** ** * +*
       *  *			      * ** *  *	 *********     * ** ** *  *
   800 *+ *			   **** ** *  *	 *  * ** *     * ** ** * +*
   700 *+ ***			****  * ** *  *	 *  * ** ****  * ** ** * +*
       *  * *		     ****  *  * ** *  *	 *  * ** *  **** ** ** *  *
   600 *+ * ****	     *	*  *  * ** *  *	 *  * ** *  *  * ** ** * +*
       *  * ** *	     *	*  *  * ** *  *	 *  * ** *  *  * ** ** *  *
   500 *+ * ** *	     *	*  *  * ** *  *	 *  * ** *  *  * ** ** * +*
       *  * ** ****	   ***	*  *  * ** *  *	 *  * ** *  *  * ** ** *  *
   400 *+ * ** ** ****	   * *	*  *  * ** *  *	 *  * ** *  *  * ** ** * +*
       *+ *+**+**+* +*******+* +* +*+ *+**+* +*+ *+ *+**+* +*+ *+**+**+* +*
   300 ********************************************************************
	0  1  2	 3  4 5	 6  7  8  910 11 12 1314 15 16 17 1819 20 21 22 23
                                       Hour

   ---------- Footnotes ----------

   (1) <http://www.gnuplot.info/>


File: mu-guile.info,  Node: Writing scripts,  Next: Recipes,  Prev: Plotting data,  Up: Top

8 Writing scripts
*****************

The mu program has built-in support for running guile-scripts, and comes
with a number of examples.

   You can get a list of all scripts with the mu script command:
$ mu script
Available scripts (use --verbose for details):
  * find-dups: find duplicate messages
  * msgs-count: count the number of messages matching some query
  * msgs-per-day: graph the number of messages per day
  * msgs-per-hour: graph the number of messages per hour
  * msgs-per-month: graph the number of messages per month
  * msgs-per-year: graph the number of messages per year
  * msgs-per-year-month: graph the number of messages per year-month

   You can then execute such a script by its name:
$ mu msgs-per-month --textonly --query=hello


                        Messages per month matching hello

  240 ++-+-----+----+-----+-----+-----+----+-----+-----+-----+----+-----+-++
      |  +     +    +     + "/tmp/filewi9H0N" using 2:xticlabels(1) ****** |
  220 ++                                       *    *                 ******
      |                                        *    *                 *    *
  200 ++                                       *    *                 *   +*
      |                                        *    *                 *    *
  180 ++                     ******            *    *                 *   +*
      |                      *    *            *    *                 *    *
  160 ******                 *    *            *    *                 *   +*
      *    *                 *    *            *    *                 *    *
      *    *******           *    *            *    *     ******      *    *
  140 *+   **    *           *    *            *    *     *    ********   +*
      *    **    *******     *    *            *    *     *    **    **    *
  120 *+   **    **    *******    *            *    *     *    **    **   +*
      *    **    **    **    *    *            *    *******    **    **    *
  100 *+   **    **    **    *    *            *    *    **    **    **   +*
      *  + **  + ** +  ** +  *  + *   +    +   * +  *  + **  + ** +  ** +  *
   80 **********************************************************************
        Jan   Feb  Mar   Apr   May   Jun  Jul   Aug   Sep   Oct  Nov   Dec
                                      Month

   Please refer to the mu-script man-page for some details on writing
your own scripts.


File: mu-guile.info,  Node: Recipes,  Next: GNU Free Documentation License,  Prev: Writing scripts,  Up: Top

Appendix A Recipes
******************

   • Calculating the average length of subject-lines
          ;; the average length of all our
          (let ((len 0) (n 0))
            (mu:for-each-message
              (lambda (msg)
                (set! len (+ len (string-length (or (mu:subject msg) ""))))
                (set! n (+ n 1))))
            (if (= n 0) 0 (/ len n)))
            ;; this gives a rational, exact result;
            ;; use exact->inexact to get decimals

          ;; we we can make this short with the mu:average (with (mu stats))
          (mu:average (lambda (msg) (string-length (or (mu:subject msg) ""))))




File: mu-guile.info,  Node: GNU Free Documentation License,  Prev: Recipes,  Up: Top

Appendix B GNU Free Documentation License
*****************************************

                      Version 1.2, November 2002

     Copyright © 2000,2001,2002 Free Software Foundation, Inc.
     51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA

     Everyone is permitted to copy and distribute verbatim copies
     of this license document, but changing it is not allowed.

  0. PREAMBLE

     The purpose of this License is to make a manual, textbook, or other
     functional and useful document “free” in the sense of freedom: to
     assure everyone the effective freedom to copy and redistribute it,
     with or without modifying it, either commercially or
     noncommercially.  Secondarily, this License preserves for the
     author and publisher a way to get credit for their work, while not
     being considered responsible for modifications made by others.

     This License is a kind of "copyleft", which means that derivative
     works of the document must themselves be free in the same sense.
     It complements the GNU General Public License, which is a copyleft
     license designed for free software.

     We have designed this License in order to use it for manuals for
     free software, because free software needs free documentation: a
     free program should come with manuals providing the same freedoms
     that the software does.  But this License is not limited to
     software manuals; it can be used for any textual work, regardless
     of subject matter or whether it is published as a printed book.  We
     recommend this License principally for works whose purpose is
     instruction or reference.

  1. APPLICABILITY AND DEFINITIONS

     This License applies to any manual or other work, in any medium,
     that contains a notice placed by the copyright holder saying it can
     be distributed under the terms of this License.  Such a notice
     grants a world-wide, royalty-free license, unlimited in duration,
     to use that work under the conditions stated herein.  The
     "Document", below, refers to any such manual or work.  Any member
     of the public is a licensee, and is addressed as "you".  You accept
     the license if you copy, modify or distribute the work in a way
     requiring permission under copyright law.

     A "Modified Version" of the Document means any work containing the
     Document or a portion of it, either copied verbatim, or with
     modifications and/or translated into another language.

     A "Secondary Section" is a named appendix or a front-matter section
     of the Document that deals exclusively with the relationship of the
     publishers or authors of the Document to the Document's overall
     subject (or to related matters) and contains nothing that could
     fall directly within that overall subject.  (Thus, if the Document
     is in part a textbook of mathematics, a Secondary Section may not
     explain any mathematics.)  The relationship could be a matter of
     historical connection with the subject or with related matters, or
     of legal, commercial, philosophical, ethical or political position
     regarding them.

     The "Invariant Sections" are certain Secondary Sections whose
     titles are designated, as being those of Invariant Sections, in the
     notice that says that the Document is released under this License.
     If a section does not fit the above definition of Secondary then it
     is not allowed to be designated as Invariant.  The Document may
     contain zero Invariant Sections.  If the Document does not identify
     any Invariant Sections then there are none.

     The "Cover Texts" are certain short passages of text that are
     listed, as Front-Cover Texts or Back-Cover Texts, in the notice
     that says that the Document is released under this License.  A
     Front-Cover Text may be at most 5 words, and a Back-Cover Text may
     be at most 25 words.

     A "Transparent" copy of the Document means a machine-readable copy,
     represented in a format whose specification is available to the
     general public, that is suitable for revising the document
     straightforwardly with generic text editors or (for images composed
     of pixels) generic paint programs or (for drawings) some widely
     available drawing editor, and that is suitable for input to text
     formatters or for automatic translation to a variety of formats
     suitable for input to text formatters.  A copy made in an otherwise
     Transparent file format whose markup, or absence of markup, has
     been arranged to thwart or discourage subsequent modification by
     readers is not Transparent.  An image format is not Transparent if
     used for any substantial amount of text.  A copy that is not
     "Transparent" is called "Opaque".

     Examples of suitable formats for Transparent copies include plain
     ASCII without markup, Texinfo input format, LaTeX input format,
     SGML or XML using a publicly available DTD, and standard-conforming
     simple HTML, PostScript or PDF designed for human modification.
     Examples of transparent image formats include PNG, XCF and JPG.
     Opaque formats include proprietary formats that can be read and
     edited only by proprietary word processors, SGML or XML for which
     the DTD and/or processing tools are not generally available, and
     the machine-generated HTML, PostScript or PDF produced by some word
     processors for output purposes only.

     The "Title Page" means, for a printed book, the title page itself,
     plus such following pages as are needed to hold, legibly, the
     material this License requires to appear in the title page.  For
     works in formats which do not have any title page as such, "Title
     Page" means the text near the most prominent appearance of the
     work's title, preceding the beginning of the body of the text.

     A section "Entitled XYZ" means a named subunit of the Document
     whose title either is precisely XYZ or contains XYZ in parentheses
     following text that translates XYZ in another language.  (Here XYZ
     stands for a specific section name mentioned below, such as
     "Acknowledgements", "Dedications", "Endorsements", or "History".)
     To "Preserve the Title" of such a section when you modify the
     Document means that it remains a section "Entitled XYZ" according
     to this definition.

     The Document may include Warranty Disclaimers next to the notice
     which states that this License applies to the Document.  These
     Warranty Disclaimers are considered to be included by reference in
     this License, but only as regards disclaiming warranties: any other
     implication that these Warranty Disclaimers may have is void and
     has no effect on the meaning of this License.

  2. VERBATIM COPYING

     You may copy and distribute the Document in any medium, either
     commercially or noncommercially, provided that this License, the
     copyright notices, and the license notice saying this License
     applies to the Document are reproduced in all copies, and that you
     add no other conditions whatsoever to those of this License.  You
     may not use technical measures to obstruct or control the reading
     or further copying of the copies you make or distribute.  However,
     you may accept compensation in exchange for copies.  If you
     distribute a large enough number of copies you must also follow the
     conditions in section 3.

     You may also lend copies, under the same conditions stated above,
     and you may publicly display copies.

  3. COPYING IN QUANTITY

     If you publish printed copies (or copies in media that commonly
     have printed covers) of the Document, numbering more than 100, and
     the Document's license notice requires Cover Texts, you must
     enclose the copies in covers that carry, clearly and legibly, all
     these Cover Texts: Front-Cover Texts on the front cover, and
     Back-Cover Texts on the back cover.  Both covers must also clearly
     and legibly identify you as the publisher of these copies.  The
     front cover must present the full title with all words of the title
     equally prominent and visible.  You may add other material on the
     covers in addition.  Copying with changes limited to the covers, as
     long as they preserve the title of the Document and satisfy these
     conditions, can be treated as verbatim copying in other respects.

     If the required texts for either cover are too voluminous to fit
     legibly, you should put the first ones listed (as many as fit
     reasonably) on the actual cover, and continue the rest onto
     adjacent pages.

     If you publish or distribute Opaque copies of the Document
     numbering more than 100, you must either include a machine-readable
     Transparent copy along with each Opaque copy, or state in or with
     each Opaque copy a computer-network location from which the general
     network-using public has access to download using public-standard
     network protocols a complete Transparent copy of the Document, free
     of added material.  If you use the latter option, you must take
     reasonably prudent steps, when you begin distribution of Opaque
     copies in quantity, to ensure that this Transparent copy will
     remain thus accessible at the stated location until at least one
     year after the last time you distribute an Opaque copy (directly or
     through your agents or retailers) of that edition to the public.

     It is requested, but not required, that you contact the authors of
     the Document well before redistributing any large number of copies,
     to give them a chance to provide you with an updated version of the
     Document.

  4. MODIFICATIONS

     You may copy and distribute a Modified Version of the Document
     under the conditions of sections 2 and 3 above, provided that you
     release the Modified Version under precisely this License, with the
     Modified Version filling the role of the Document, thus licensing
     distribution and modification of the Modified Version to whoever
     possesses a copy of it.  In addition, you must do these things in
     the Modified Version:

       A. Use in the Title Page (and on the covers, if any) a title
          distinct from that of the Document, and from those of previous
          versions (which should, if there were any, be listed in the
          History section of the Document).  You may use the same title
          as a previous version if the original publisher of that
          version gives permission.

       B. List on the Title Page, as authors, one or more persons or
          entities responsible for authorship of the modifications in
          the Modified Version, together with at least five of the
          principal authors of the Document (all of its principal
          authors, if it has fewer than five), unless they release you
          from this requirement.

       C. State on the Title page the name of the publisher of the
          Modified Version, as the publisher.

       D. Preserve all the copyright notices of the Document.

       E. Add an appropriate copyright notice for your modifications
          adjacent to the other copyright notices.

       F. Include, immediately after the copyright notices, a license
          notice giving the public permission to use the Modified
          Version under the terms of this License, in the form shown in
          the Addendum below.

       G. Preserve in that license notice the full lists of Invariant
          Sections and required Cover Texts given in the Document's
          license notice.

       H. Include an unaltered copy of this License.

       I. Preserve the section Entitled "History", Preserve its Title,
          and add to it an item stating at least the title, year, new
          authors, and publisher of the Modified Version as given on the
          Title Page.  If there is no section Entitled "History" in the
          Document, create one stating the title, year, authors, and
          publisher of the Document as given on its Title Page, then add
          an item describing the Modified Version as stated in the
          previous sentence.

       J. Preserve the network location, if any, given in the Document
          for public access to a Transparent copy of the Document, and
          likewise the network locations given in the Document for
          previous versions it was based on.  These may be placed in the
          "History" section.  You may omit a network location for a work
          that was published at least four years before the Document
          itself, or if the original publisher of the version it refers
          to gives permission.

       K. For any section Entitled "Acknowledgements" or "Dedications",
          Preserve the Title of the section, and preserve in the section
          all the substance and tone of each of the contributor
          acknowledgements and/or dedications given therein.

       L. Preserve all the Invariant Sections of the Document, unaltered
          in their text and in their titles.  Section numbers or the
          equivalent are not considered part of the section titles.

       M. Delete any section Entitled "Endorsements".  Such a section
          may not be included in the Modified Version.

       N. Do not retitle any existing section to be Entitled
          "Endorsements" or to conflict in title with any Invariant
          Section.

       O. Preserve any Warranty Disclaimers.

     If the Modified Version includes new front-matter sections or
     appendices that qualify as Secondary Sections and contain no
     material copied from the Document, you may at your option designate
     some or all of these sections as invariant.  To do this, add their
     titles to the list of Invariant Sections in the Modified Version's
     license notice.  These titles must be distinct from any other
     section titles.

     You may add a section Entitled "Endorsements", provided it contains
     nothing but endorsements of your Modified Version by various
     parties--for example, statements of peer review or that the text
     has been approved by an organization as the authoritative
     definition of a standard.

     You may add a passage of up to five words as a Front-Cover Text,
     and a passage of up to 25 words as a Back-Cover Text, to the end of
     the list of Cover Texts in the Modified Version.  Only one passage
     of Front-Cover Text and one of Back-Cover Text may be added by (or
     through arrangements made by) any one entity.  If the Document
     already includes a cover text for the same cover, previously added
     by you or by arrangement made by the same entity you are acting on
     behalf of, you may not add another; but you may replace the old
     one, on explicit permission from the previous publisher that added
     the old one.

     The author(s) and publisher(s) of the Document do not by this
     License give permission to use their names for publicity for or to
     assert or imply endorsement of any Modified Version.

  5. COMBINING DOCUMENTS

     You may combine the Document with other documents released under
     this License, under the terms defined in section 4 above for
     modified versions, provided that you include in the combination all
     of the Invariant Sections of all of the original documents,
     unmodified, and list them all as Invariant Sections of your
     combined work in its license notice, and that you preserve all
     their Warranty Disclaimers.

     The combined work need only contain one copy of this License, and
     multiple identical Invariant Sections may be replaced with a single
     copy.  If there are multiple Invariant Sections with the same name
     but different contents, make the title of each such section unique
     by adding at the end of it, in parentheses, the name of the
     original author or publisher of that section if known, or else a
     unique number.  Make the same adjustment to the section titles in
     the list of Invariant Sections in the license notice of the
     combined work.

     In the combination, you must combine any sections Entitled
     "History" in the various original documents, forming one section
     Entitled "History"; likewise combine any sections Entitled
     "Acknowledgements", and any sections Entitled "Dedications".  You
     must delete all sections Entitled "Endorsements."

  6. COLLECTIONS OF DOCUMENTS

     You may make a collection consisting of the Document and other
     documents released under this License, and replace the individual
     copies of this License in the various documents with a single copy
     that is included in the collection, provided that you follow the
     rules of this License for verbatim copying of each of the documents
     in all other respects.

     You may extract a single document from such a collection, and
     distribute it individually under this License, provided you insert
     a copy of this License into the extracted document, and follow this
     License in all other respects regarding verbatim copying of that
     document.

  7. AGGREGATION WITH INDEPENDENT WORKS

     A compilation of the Document or its derivatives with other
     separate and independent documents or works, in or on a volume of a
     storage or distribution medium, is called an "aggregate" if the
     copyright resulting from the compilation is not used to limit the
     legal rights of the compilation's users beyond what the individual
     works permit.  When the Document is included in an aggregate, this
     License does not apply to the other works in the aggregate which
     are not themselves derivative works of the Document.

     If the Cover Text requirement of section 3 is applicable to these
     copies of the Document, then if the Document is less than one half
     of the entire aggregate, the Document's Cover Texts may be placed
     on covers that bracket the Document within the aggregate, or the
     electronic equivalent of covers if the Document is in electronic
     form.  Otherwise they must appear on printed covers that bracket
     the whole aggregate.

  8. TRANSLATION

     Translation is considered a kind of modification, so you may
     distribute translations of the Document under the terms of section
     4.  Replacing Invariant Sections with translations requires special
     permission from their copyright holders, but you may include
     translations of some or all Invariant Sections in addition to the
     original versions of these Invariant Sections.  You may include a
     translation of this License, and all the license notices in the
     Document, and any Warranty Disclaimers, provided that you also
     include the original English version of this License and the
     original versions of those notices and disclaimers.  In case of a
     disagreement between the translation and the original version of
     this License or a notice or disclaimer, the original version will
     prevail.

     If a section in the Document is Entitled "Acknowledgements",
     "Dedications", or "History", the requirement (section 4) to
     Preserve its Title (section 1) will typically require changing the
     actual title.

  9. TERMINATION

     You may not copy, modify, sublicense, or distribute the Document
     except as expressly provided for under this License.  Any other
     attempt to copy, modify, sublicense or distribute the Document is
     void, and will automatically terminate your rights under this
     License.  However, parties who have received copies, or rights,
     from you under this License will not have their licenses terminated
     so long as such parties remain in full compliance.

  10. FUTURE REVISIONS OF THIS LICENSE

     The Free Software Foundation may publish new, revised versions of
     the GNU Free Documentation License from time to time.  Such new
     versions will be similar in spirit to the present version, but may
     differ in detail to address new problems or concerns.  See
     <http://www.gnu.org/copyleft/>.

     Each version of the License is given a distinguishing version
     number.  If the Document specifies that a particular numbered
     version of this License "or any later version" applies to it, you
     have the option of following the terms and conditions either of
     that specified version or of any later version that has been
     published (not as a draft) by the Free Software Foundation.  If the
     Document does not specify a version number of this License, you may
     choose any version ever published (not as a draft) by the Free
     Software Foundation.

ADDENDUM: How to use this License for your documents
====================================================

To use this License in a document you have written, include a copy of
the License in the document and put the following copyright and license
notices just after the title page:

       Copyright (C)  YEAR  YOUR NAME.
       Permission is granted to copy, distribute and/or modify this document
       under the terms of the GNU Free Documentation License, Version 1.2
       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''.

   If you have Invariant Sections, Front-Cover Texts and Back-Cover
Texts, replace the "with...Texts."  line with this:

         with the Invariant Sections being LIST THEIR TITLES, with
         the Front-Cover Texts being LIST, and with the Back-Cover Texts
         being LIST.

   If you have Invariant Sections without Cover Texts, or some other
combination of the three, merge those two alternatives to suit the
situation.

   If your document contains nontrivial examples of program code, we
recommend releasing these examples in parallel under your choice of free
software license, such as the GNU General Public License, to permit
their use in free software.



Tag Table:
Node: Top691
Node: Getting started1901
Node: Installation2159
Ref: Installation-Footnote-14990
Ref: Installation-Footnote-25051
Node: Making sure it works5180
Node: Initializing mu-guile6460
Ref: Initializing mu-guile-Footnote-18177
Ref: Initializing mu-guile-Footnote-28230
Node: Messages8336
Node: Finding messages8737
Ref: Finding messages-Footnote-110693
Node: Message methods10964
Node: Example - the longest subject13934
Node: Contacts15198
Node: Contact procedures and objects15722
Node: All contacts17157
Node: Utility procedures18565
Node: Example - mutt export19124
Ref: Example - mutt export-Footnote-120847
Node: Attachments and other parts20878
Node: Parts and their methods21197
Node: Attachment example22089
Node: Statistics23291
Node: Basics23694
Node: Tabulating values25119
Node: Most frequent values27017
Ref: Most frequent values-Footnote-128006
Node: Plotting data28059
Ref: Plotting data-Footnote-130660
Node: Writing scripts30695
Node: Recipes33206
Node: GNU Free Documentation License33958

End Tag Table


Local Variables:
coding: utf-8
End:
