* mu-guile.texi: updated / expanded documentation
This commit is contained in:
@ -37,6 +37,9 @@ programming language.
|
||||
* Initializing mu-guile::
|
||||
* Messages::
|
||||
* Contacts::
|
||||
* Attachments and other parts::
|
||||
* Statistics::
|
||||
* Plotting data::
|
||||
|
||||
Appendices
|
||||
|
||||
@ -446,7 +449,7 @@ A contact object (@code{<mu-contact>}) has two methods:
|
||||
Let's get a list of all names and e-mail addresses in the 'To:' field, of
|
||||
messages matching 'book':
|
||||
|
||||
@verbatim
|
||||
@lisp
|
||||
(use-modules (mu) (mu message) (mu contact))
|
||||
(mu:initialize)
|
||||
(mu:for-each-message
|
||||
@ -457,7 +460,7 @@ messages matching 'book':
|
||||
(or (email contact) "") (or (name contact) "no-name")))
|
||||
(contacts msg mu:to)))
|
||||
"book")
|
||||
@end verbatim
|
||||
@end lisp
|
||||
|
||||
This shows what the methods do, but for many uses, it would be more useful to
|
||||
have each of the contacts only show up @emph{once} - for that, please refer to
|
||||
@ -515,22 +518,232 @@ It is a bit hard to @emph{guess} the nick name for e-mail contacts, so we are
|
||||
going to assume it is the lowercase version of the first word in
|
||||
@t{<name>}. You can always adjust them later by hand, obviously.
|
||||
|
||||
@verbatim
|
||||
@lisp
|
||||
#!/bin/sh
|
||||
exec guile -s $0 $@
|
||||
!#
|
||||
(use-modules (mu) (mu message) (mu contact))
|
||||
(mu:initialize)
|
||||
|
||||
(mu:for-each-contact
|
||||
(lambda (contact)
|
||||
(define (selected-contacts)
|
||||
"Get a list of contacts that were seen at least 20 times since
|
||||
2010."
|
||||
(let ((addrs '())
|
||||
(start (car (mktime (car (strptime "%F" "2010-01-01")))))
|
||||
(minfreq 20))
|
||||
(mu:for-each-contact
|
||||
(lambda (contact)
|
||||
(if (and (email contact)
|
||||
(>= (frequency contact) minfreq)
|
||||
(>= (last-seen contact) start))
|
||||
(set! addrs (cons contact addrs)))))
|
||||
addrs))
|
||||
|
||||
(define (guess-nick contact)
|
||||
"Guess a nick name for CONTACT."
|
||||
(string-map
|
||||
(lambda(kar)
|
||||
(if (char-alphabetic? kar) kar #\_))
|
||||
(string-downcase (or (name contact) (email contact)))))
|
||||
|
||||
(for-each
|
||||
(lambda (contact)
|
||||
(format #t "alias ~a ~a <~a>\n"
|
||||
(guess-nick contact) (name contact) (email contact)))
|
||||
(selected-contacts))
|
||||
@end lisp
|
||||
|
||||
This simple program could be improved in many ways; this is left as an
|
||||
excercise to the reader.
|
||||
|
||||
@node Attachments and other parts
|
||||
@chapter Attachments and other parts
|
||||
|
||||
To deal with @emph{attachments}, or, more in general @emph{MIME-parts}, there
|
||||
is the @t{mu part} module.
|
||||
|
||||
@menu
|
||||
* Parts and their methods::
|
||||
* Attachment example::
|
||||
@end menu
|
||||
|
||||
@node Parts and their methods
|
||||
@section Parts and their methods
|
||||
The module defines the @code{<mu-part>} class, and adds two methods to
|
||||
@code{<mu-message>} objects:
|
||||
@itemize
|
||||
@item @code{(parts msg)} - returns a list @code{<mu-part>} objects, one for
|
||||
each MIME-parts in the message.
|
||||
@item @code{(attachments)} - like @code{parts}, but only list those MIME-parts
|
||||
that look like proper attachments.
|
||||
@end itemize
|
||||
|
||||
A @code{<mu-part>} object exposes a few methods to get information about the
|
||||
part:
|
||||
@itemize
|
||||
@item @code{name} - returns the file name of the mime-part, or @code{#f} if
|
||||
there is none.
|
||||
@item @code{mime-type} - returns the mime-type of the mime-part, or @code{#f}
|
||||
if there is none.
|
||||
@item @code{size} - returns the size in bytes of the mime-part
|
||||
@end itemize
|
||||
|
||||
Then, we may want to save the part to a file; this can be done using either:
|
||||
@itemize
|
||||
@item @code{(save part)} - save a part to a temporary file, return the file
|
||||
name@footnote{the temporary filename is a predictable function of (user-id,
|
||||
msg-path, part-index)}
|
||||
@item @code{(save-as part path)} - save part to file at path
|
||||
@end itemize
|
||||
|
||||
@node Attachment example
|
||||
@section Attachment example
|
||||
|
||||
Let's look at some small examples.
|
||||
|
||||
First, let's get a list of the biggest attachments in messages about
|
||||
Luxemburg:
|
||||
|
||||
@lisp
|
||||
#!/bin/sh
|
||||
exec guile -s $0 $@
|
||||
!#
|
||||
|
||||
(use-modules (mu) (mu message) (mu part))
|
||||
(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 (name att) (or (size att) 0)) pairs)))
|
||||
(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)))))
|
||||
@end lisp
|
||||
|
||||
As an exercise for the reader, you might want to re-rewrite the
|
||||
@code{all-attachments} in terms of @code{mu:message-list}, which would
|
||||
probably be a bit more elegant.
|
||||
|
||||
|
||||
@node Statistics
|
||||
@chapter Statistics
|
||||
|
||||
@t{mu-guile} offers some convenience functions to determine various statistics
|
||||
about the messages in the database.
|
||||
|
||||
First, there is @code{(mu:tabulate-messages <function> [<search-expr>])}. This
|
||||
function applies @t{<function>} to each message matching @t{<search-expr>}
|
||||
(leave empty to match @emph{all} messages), and returns a associative list
|
||||
with each of the different results of @t{<function>} and their frequencies.
|
||||
|
||||
This can best be demonstrated with a little example. Suppose we want to know
|
||||
how many messages we receive per weekday:
|
||||
|
||||
@lisp
|
||||
#!/bin/sh
|
||||
exec guile -s $0 $@
|
||||
!#
|
||||
|
||||
(use-modules (mu) (mu message) (mu stats))
|
||||
(mu:initialize)
|
||||
|
||||
(define (weekday-table)
|
||||
"Returns something like
|
||||
'((0 . 12) (5 . 20) (2 . 16) ... )
|
||||
that is, an unsorted list of (<weekday> . <frequency>)."
|
||||
(mu:tabulate-messages
|
||||
(lambda (msg)
|
||||
(tm:wday (localtime (date msg))))))
|
||||
|
||||
;; sort & display
|
||||
(let ((table (weekday-table)))
|
||||
(for-each
|
||||
(lambda (pair)
|
||||
(let ((days '("Sun" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat")))
|
||||
(format #t "~a: ~a\n"
|
||||
(list-ref days (car pair)) (cdr pair))))
|
||||
(sort (weekday-table)(lambda (a b) (< (car a) (car b))))))
|
||||
@end lisp
|
||||
|
||||
The function @code{weekday-table} use @code{mu:tabulate-message} to get the
|
||||
frequencies per hour -- this returns a list of pairs:
|
||||
@verbatim
|
||||
((5 . 2339) (0 . 2278) (4 . 2800) (2 . 3184) (6 . 1856) (3 . 2833) (1 . 2993))
|
||||
@end verbatim
|
||||
|
||||
The script then output these numbers in following form:
|
||||
|
||||
@verbatim
|
||||
Sun: 2278
|
||||
Mon: 2993
|
||||
Tue: 3184
|
||||
Wed: 2833
|
||||
Thu: 2800
|
||||
Fri: 2339
|
||||
Sat: 1856
|
||||
@end verbatim
|
||||
|
||||
Clearly, Saturday is a slow day for e-mail...
|
||||
|
||||
@node Plotting data
|
||||
@chapter Plotting data
|
||||
|
||||
@lisp
|
||||
#!/bin/sh
|
||||
exec guile -s $0 $@
|
||||
!#
|
||||
|
||||
(use-modules (mu) (mu message) (mu contact) (mu stats) (mu plot))
|
||||
(mu:initialize)
|
||||
|
||||
(define (mail-per-hour-table)
|
||||
(sort
|
||||
(mu:tabulate-messages
|
||||
(lambda (msg)
|
||||
(tm:hour (localtime (date msg)))))
|
||||
(lambda (x y) (< (car x) (car y)))))
|
||||
|
||||
(mu:plot-ascii (mail-per-hour-table) "Mail per hour" "Hour" "Frequency")
|
||||
@end lisp
|
||||
|
||||
@verbatim
|
||||
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
|
||||
@end verbatim
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user