Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Titus von der Malsburg 2013-03-17 20:42:44 +01:00
commit a4e714d9ea
23 changed files with 244 additions and 328 deletions

View File

@ -110,6 +110,11 @@ AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
glib_version="`$PKG_CONFIG --modversion glib-2.0`"
PKG_CHECK_MODULES(GIO,gio-2.0,[have_gio=yes],[have_gio=no])
AC_SUBST(GIO_CFLAGS)
AC_SUBST(GIO_LIBS)
gio_version="`$PKG_CONFIG --modversion gio-2.0`"
# gmime 2.4 or 2.6?
PKG_CHECK_MODULES(GMIME,gmime-2.6,[have_gmime_26=yes],[have_gmime_26=no])
AS_IF([test "x$have_gmime_26" = "xno"],[
@ -169,82 +174,28 @@ AC_DEFINE(MU_STORE_SCHEMA_VERSION,["9.9"], ['Schema' version of the database])
###############################################################################
# we need gtk (2 or 3) for some of the graphical tools
#
AC_ARG_WITH([gui],
[AS_HELP_STRING([--with-gui=gtk2|gtk3|none])],
[gui=$withval],[gui=auto])
AS_IF([test "x$gui" != "xgtk2" -a "x$gui" != "xgtk3" -a "x$gui" != "xnone" \
-a "x$gui" != "xauto"],
AC_MSG_ERROR([the argument for --with-gui= must be either \
gtk2|gtk3|auto|no ($gui)]))
AS_IF([test "x$gui" != "xnone"],[
# check for gtk3
AS_IF([test "x$gui" = "xgtk3"],[
PKG_CHECK_MODULES(GTK,gtk+-3.0,[have_gtk3=yes],[have_gtk3=no])
# we need GTK+3 for some of the graphical tools
# use --without-gtk to disable it
AC_ARG_ENABLE([gtk],AS_HELP_STRING([--disable-gtk],[Disable GTK+]))
AS_IF([test "x$enable_gtk" != "xno"],[
PKG_CHECK_MODULES(GTK,gtk+-3.0,[have_gtk=yes],[have_gtk=no])
AC_SUBST(GTK_CFLAGS)
AC_SUBST(GTK_LIBS)
gtk_version="`$PKG_CONFIG --modversion gtk+-3.0`"
])
AS_IF([test "x$gui"="gtk3" -a "x$have_gtk3" = "xno"],
AC_MSG_ERROR([GTK+ 3.x not found]))
# check for gtk2 if we did not find gtk3 already
# (gtk3 is only sought if asked for it explicitly)
AS_IF([test "x$gui" != "xno" -a "x$have_gtk3" != "xyes"],[
PKG_CHECK_MODULES(GTK,gtk+-2.0,[have_gtk2=yes],[have_gtk2=no])
AC_SUBST(GTK_CFLAGS)
AC_SUBST(GTK_LIBS)
gtk_version="`$PKG_CONFIG --modversion gtk+-2.0`"
])
# only an error if we explicitly asked for it
AS_IF([test "x$have_gtk2" = "xno" -a "x$gui" != "xauto"],
AC_MSG_ERROR([GTK+ 2.x not found]))
])
AM_CONDITIONAL(HAVE_GTK,[test "x$have_gtk2" = "xyes" -o "x$have_gtk3" = "xyes" ])
AS_IF([test "x$have_gtk2" = "xyes" -o "x$have_gtk3" = "xyes"],[buildgui=yes],
[buildgui=no])
AS_IF([test "x$have_gtk3" = "xyes"],
[AC_DEFINE_UNQUOTED([HAVE_GTK3],1,[Whether we have GTK+ 3.x])])
gtk_version="`$PKG_CONFIG --modversion gtk+-3.0`"])
AM_CONDITIONAL(HAVE_GTK,[test "x$have_gtk" = "xyes"])
# webkit? needed for the fancy web widget
# use --disable-webkit to disable it, even if you have it
# note; gtk2 and gtk3 imply different webkit versions
build_webkit=no
AC_ARG_ENABLE([webkit],
AS_HELP_STRING([--disable-webkit],[Disable webkit]))
AS_IF([test "x$enable_webkit" != "xno"], [
AS_IF([test "x$have_gtk2" = "xyes"],[
PKG_CHECK_MODULES(WEBKIT,webkit-1.0 >= 1.0.3,[build_webkit=yes],[build_webkit=no])
AS_IF([test "x$build_webkit" = "xyes"],[
webkit_version="`$PKG_CONFIG --modversion webkit-1.0`"])
AC_SUBST(WEBKIT_CFLAGS)
AC_SUBST(WEBKIT_LIBS)])
AS_IF([test "x$have_gtk3" = "xyes"],[
PKG_CHECK_MODULES(WEBKIT,webkitgtk-3.0 >= 1.8.0, [build_webkit=yes],[build_webkit=no])
AS_IF([test "x$build_webkit" = "xyes"],[
AC_ARG_ENABLE([webkit],AS_HELP_STRING([--disable-webkit],[Disable webkit]))
AS_IF([test "x$enable_webkit" != "xno"],[
PKG_CHECK_MODULES(WEBKIT,webkitgtk-3.0 >= 1.8.0,[have_webkit=yes],[have_webkit=no])
AS_IF([test "x$have_webkit" = "xyes"],[
webkit_version="`$PKG_CONFIG --modversion webkitgtk-3.0`"])
AC_SUBST(WEBKIT_CFLAGS)
AC_SUBST(WEBKIT_LIBS)])
AC_SUBST(WEBKIT_LIBS)
])
AM_CONDITIONAL(BUILD_WEBKIT, [test "x$build_webkit" = "xyes"])
# gio is needed for some widget/ things
AS_IF([test "x$buildgui"="xyes"],[
PKG_CHECK_MODULES(GIO,gio-2.0,[have_gio=yes],[have_gio=no])
AS_IF([test "x$have_gio" = "xyes"],[
gio_version="`$PKG_CONFIG --modversion gio-2.0`"])
AC_SUBST(GIO_CFLAGS)
AC_SUBST(GIO_LIBS)
])
AM_CONDITIONAL(HAVE_GIO, [test "x$have_gio" = "xyes"])
# should we build the gui toys?
AM_CONDITIONAL(BUILD_GUI, [test "x$build_webkit" = "xyes" -a "x$have_gio" = "xyes"])
AM_CONDITIONAL(HAVE_WEBKIT, [test "x$have_webkit" = "xyes"])
AM_CONDITIONAL(BUILD_GUI,[test "x$have_webkit" = "xyes" -a "x$have_gtk" = "xyes"])
###############################################################################
@ -344,21 +295,10 @@ echo "Xapian version : $xapian_version"
echo "GLib version : $glib_version"
echo "GMime version : $gmime_version"
if test "x$buildgui" = "xyes"; then
AM_COND_IF([BUILD_GUI],[
echo "GTK+ version : $gtk_version"
fi
if test "x$have_gio" = "xyes"; then
echo "GIO version : $gio_version"
fi
if test "x$build_webkit" = "xyes"; then
echo "Webkit version : $webkit_version"
fi
if test "x$build_guile" = "xyes"; then
echo "Guile version : $guile_version"
fi
])
if test "x$build_mu4e" = "xyes"; then
echo "Emacs version : $emacs_version"
@ -368,7 +308,11 @@ echo
echo "Have wordexp : $ac_cv_header_wordexp_h"
echo "Build mu4e emacs frontend : $build_mu4e"
echo "Build crypto support (gmime >= 2.6) : $have_gmime_26"
echo "Build 'mug' toy-ui (gtk+/webkit) : $buildgui"
AM_COND_IF([BUILD_GUI],[
echo "Build 'mug' toy-ui (gtk+/webkit) : yes"],[
echo "Build 'mug' toy-ui (gtk+/webkit) : no"
])
echo "McCabe's Cyclomatic Complexity tool : $have_pmccabe"
echo
@ -395,10 +339,6 @@ if test "x$buildgui" = "xyes"; then
echo
fi
# the unit tests
echo "* You can run 'make check' to run the unit tests"
echo
# wordexp
if test "x$ac_cv_header_wordexp_h" != "xyes"; then
echo "* Your system does not seem to have the 'wordexp' function."
@ -410,5 +350,5 @@ if test "x$ac_cv_header_wordexp_h" != "xyes"; then
fi
echo
echo "Now, type 'make' to build mu."
echo "Now, type 'make' to build mu (or 'make check' to run the unit tests, too)"
echo

View File

@ -166,8 +166,9 @@ static const MuMsgField FIELD_DATA[] = {
{
MU_MSG_FIELD_ID_MAILING_LIST,
MU_MSG_FIELD_TYPE_STRING,
"list", 'v', 'L',
FLAG_GMIME | FLAG_XAPIAN_VALUE
"list", 'v', 'V',
FLAG_GMIME | FLAG_XAPIAN_TERM | FLAG_XAPIAN_VALUE |
FLAG_XAPIAN_ESCAPE
},

View File

@ -405,7 +405,10 @@ const MuMsgIterThreadInfo*
mu_msg_iter_get_thread_info (MuMsgIter *iter)
{
g_return_val_if_fail (!mu_msg_iter_is_done(iter), NULL);
g_return_val_if_fail (iter->thread_hash(), NULL);
/* maybe we don't have thread info */
if (!iter->thread_hash())
return NULL;
try {
const MuMsgIterThreadInfo *ti;

View File

@ -179,6 +179,7 @@ typedef struct _MuMsgIterThreadInfo MuMsgIterThreadInfo;
/**
* get a the MuMsgThreaderInfo struct for this message; this only
* works when you created the mu-msg-iter with threading enabled
* (otherwise, return NULL)
*
* @param iter a valid MuMsgIter iterator
*

View File

@ -1,4 +1,4 @@
.TH MU SCRIPT 1 "October 2012" "User Manuals"
.TH MU SCRIPT 1 "March 2013" "User Manuals"
.SH NAME
@ -81,3 +81,4 @@ Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
.SH "SEE ALSO"
.BR mu(1)
.BR guile(1)

View File

@ -1,4 +1,4 @@
.TH MU 1 "January 2012" "User Manuals"
.TH MU 1 "March 2013" "User Manuals"
.SH NAME
@ -7,19 +7,41 @@ index and search e-mail messages.
.SH SYNOPSIS
In alphabetical order:
.B mu [options]
general mu command
.B mu index [options]
.B mu find [options] <search expression>
.B mu view <file> [<files>]
.B mu mkdir [options] <dir> [<dirs>]
.B mu extract [options] <file> [<parts>] [<regexp>]
.B mu add
add specific messages to the database
.B mu cfind [options] [<regexp>]
find contacts
.B mu extract [options] <file> [<parts>] [<regexp>]
extract attachments and other MIME-parts
.B mu find [options] <search expression>
find messages
.B mu index [options]
(re)index the messages in a Maildir
.B mu mkdir [options] <dir> [<dirs>]
create a new Maildir
.B mu remove [options]
remove specific messages from the database
.B mu script [options]
run a mu (Guile) script
.B mu server [options]
start a server process (for \fBmu4e\fR-internal use)
.B mu view <file> [<files>]
view a specific message
.SH DESCRIPTION
@ -176,34 +198,34 @@ non-zero when some error occured. The table lists the various error codes.
.nf
exit code | error
----------+-------------------------------------------
1 | MU_ERROR
2 | MU_ERROR_IN_PARAMETERS
3 | MU_ERROR_INTERNAL
4 | MU_ERROR_NO_MATCHES
|
11 | MU_ERROR_XAPIAN
|
13 | MU_ERROR_XAPIAN_QUERY
14 | MU_ERROR_XAPIAN_DIR_NOT_ACCESSIBLE
15 | MU_ERROR_XAPIAN_NOT_UP_TO_DATE
16 | MU_ERROR_XAPIAN_MISSING_DATA
17 | MU_ERROR_XAPIAN_CORRUPTION
18 | MU_ERROR_XAPIAN_CANNOT_GET_WRITELOCK
30 | MU_ERROR_GMIME
|
50 | MU_ERROR_CONTACTS
51 | MU_ERROR_CONTACTS_CANNOT_RETRIEVE
|
70 | MU_ERROR_FILE
71 | MU_ERROR_FILE_INVALID_NAME
72 | MU_ERROR_FILE_CANNOT_LINK
73 | MU_ERROR_FILE_CANNOT_OPEN
74 | MU_ERROR_FILE_CANNOT_READ
75 | MU_ERROR_FILE_CANNOT_CREATE
76 | MU_ERROR_FILE_CANNOT_MKDIR
77 | MU_ERROR_FILE_STAT_FAILED
78 | MU_ERROR_FILE_READDIR_FAILED
79 | MU_ERROR_FILE_INVALID_SOURCE
1 | MU_ERROR
2 | MU_ERROR_IN_PARAMETERS
3 | MU_ERROR_INTERNAL
4 | MU_ERROR_NO_MATCHES
|
11 | MU_ERROR_XAPIAN
|
13 | MU_ERROR_XAPIAN_QUERY
14 | MU_ERROR_XAPIAN_DIR_NOT_ACCESSIBLE
15 | MU_ERROR_XAPIAN_NOT_UP_TO_DATE
16 | MU_ERROR_XAPIAN_MISSING_DATA
17 | MU_ERROR_XAPIAN_CORRUPTION
18 | MU_ERROR_XAPIAN_CANNOT_GET_WRITELOCK
30 | MU_ERROR_GMIME
|
50 | MU_ERROR_CONTACTS
51 | MU_ERROR_CONTACTS_CANNOT_RETRIEVE
|
70 | MU_ERROR_FILE
71 | MU_ERROR_FILE_INVALID_NAME
72 | MU_ERROR_FILE_CANNOT_LINK
73 | MU_ERROR_FILE_CANNOT_OPEN
74 | MU_ERROR_FILE_CANNOT_READ
75 | MU_ERROR_FILE_CANNOT_CREATE
76 | MU_ERROR_FILE_CANNOT_MKDIR
77 | MU_ERROR_FILE_STAT_FAILED
78 | MU_ERROR_FILE_READDIR_FAILED
79 | MU_ERROR_FILE_INVALID_SOURCE
.fi
.SH BUGS

View File

@ -148,7 +148,8 @@ check_params (MuConfig *opts, GError **err)
{
if (!mu_util_supports (MU_FEATURE_GUILE | MU_FEATURE_GNUPLOT)) {
mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS,
"the 'script' command is not supported");
"the 'script' command is not available "
"in this version of mu");
return FALSE;
}

View File

@ -529,7 +529,7 @@ show_usage (void)
{
g_print ("usage: mu command [options] [parameters]\n");
g_print ("where command is one of index, find, cfind, view, mkdir, "
"extract, add, remove, stats, verify or server\n");
"extract, add, remove, script, verify or server\n");
g_print ("see the mu, mu-<command> or mu-easy manpages for "
"more information\n");
}

View File

@ -1,6 +1,6 @@
#-*-mode:org-*-
#
# Copyright (C) 2012 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
# Copyright (C) 2012-2013 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -83,7 +83,7 @@ is one of:
index - index messages
mkdir - create a maildir
remove - remove a message from the database
script - run a script
script - run a script (available only when mu was built with guile-support)
server - start mu server
verify - verify signatures of a message
view - view a specific message

View File

@ -187,7 +187,28 @@ store your org-contacts."
Make sure it is one of the headers mu recognizes for storing
tags: X-Keywords, X-Label, Keywords. Also note that changing
this setting on already tagged messages can lead to messages
with multiple tags headers")
with multiple tags headers.")
(defun mu4e~contains-line-matching (regexp path)
"Determine whether the file at path contains a line matching
the given regexp."
(with-temp-buffer
(insert-file-contents path)
(save-excursion
(goto-char (point-min))
(if (re-search-forward regexp nil t)
t
nil))))
(defun mu4e~replace-first-line-matching (regexp to-string path)
"Replace the first line in the file at path that matches regexp
with the string replace."
(with-temp-file path
(insert-file-contents path)
(save-excursion
(goto-char (point-min))
(if (re-search-forward regexp nil t)
(replace-match to-string nil nil)))))
(defun mu4e-action-retag-message (msg &optional retag-arg)
"Change tags of a message. Example: +tag \"+long tag\" -oldtag
@ -203,28 +224,31 @@ store your org-contacts."
(t ", ")))
(taglist (if oldtags (copy-sequence oldtags) '()))
tagstr)
(dolist (tag (split-string-and-unquote retag) taglist)
(cond ((string-match "\\+\\(.+\\)" tag)
(setq taglist (push (match-string 1 tag) taglist)))
((string-match "\\-\\(.+\\)" tag)
(cond
((string-match "^\\+\\(.+\\)" tag)
(setq taglist (push (match-string 1 tag) taglist)))
((string-match "^\\-\\(.+\\)" tag)
(setq taglist (delete (match-string 1 tag) taglist)))
(t
(setq taglist (push tag taglist)))))
(setq taglist (sort (delete-dups taglist) 'string<))
(setq tagstr (mapconcat 'identity taglist sep))
(setq tagstr (replace-regexp-in-string "[\\/&]" "\\\\\\&" tagstr))
(if (string= (shell-command-to-string (format "sed -n '1,/^$/ {/^%s:/I p}' \"%s\""
mu4e-action-tags-header path)) "")
;; Add tags header just before the content
(call-process "sed" nil nil nil "-i"
(format "1,/^$/s/^$/%s: %s\\n/I" header tagstr) path)
(setq tagstr (replace-regexp-in-string "[\\&]" "\\\\\\&" tagstr))
(setq tagstr (replace-regexp-in-string "[/]" "\\&" tagstr))
;; replaces keywords with sed, restricted to the header
(call-process "sed" nil nil nil "-i"
(format "1,/^$/s/^%s:.*$/%s: %s/I" header header tagstr) path))
(if (not (mu4e~contains-line-matching (concat header ":.*") path))
;; Add tags header just before the content
(mu4e~replace-first-line-matching
"^$" (concat header ": " tagstr "\n") path)
;; replaces keywords, restricted to the header
(mu4e~replace-first-line-matching
(concat header ":.*")
(concat header ": " tagstr)
path))
(mu4e-message (concat "tagging: " (mapconcat 'identity taglist ", ")))
(mu4e-refresh-message path maildir)))

View File

@ -27,7 +27,7 @@ Documentation License.''
@end copying
@titlepage
@title @t{mu4e} - an e-mail client for emacs
@title @t{mu4e} - an e-mail client for Emacs
@subtitle version @value{mu-version}
@author Dirk-Jan C. Binnema
@ -39,7 +39,7 @@ Documentation License.''
@dircategory Emacs
@direntry
* mu4e: (mu4e). An email client for emacs.
* mu4e: (mu4e). An email client for Emacs.
@end direntry
@contents
@ -56,12 +56,12 @@ Documentation License.''
Welcome to @t{mu4e}!
@t{mu4e} (@t{mu}-for-@command{emacs}) is an e-mail client for GNU-Emacs version 23
and later, built on top of the
@t{mu4e} (@t{mu}-for-emacs) is an e-mail client for GNU-Emacs version 23 and
later, built on top of the
@t{mu}@footnote{@url{http://www.djcbsoftware.nl/code/mu}} e-mail search
engine. @t{mu4e} is optimized for fast handling of large amounts of e-mail.
Some of its key characteristics include:
Some of mu4e's highlights:
@itemize
@item Fully search-based: there are no folders@footnote{that is, instead of
@ -71,20 +71,21 @@ queries
@item User-interface optimized for speed, with quick key strokes for common actions
@item Support for non-English languages (so ``angstrom'' will match ``Ångström'')
@item Asynchronous; heavy actions don't block @command{emacs}@footnote{currently,
the only exception to this is @emph{sending mail}}
the only exception to this is @emph{sending mail}; there are solutions for
that though - see the @ref{FAQ}}
@item Support for crypto
@item Writing rich-text e-mails using @t{org-mode}
@item Address auto-completion based on your messages
@item Extendable with your own code
@item Address auto-completion based on the contacts in your messages
@item Extendable with your own snippets of elisp
@end itemize
In this manual, we go through the installation of @t{mu4e}, do some basic
configuration and explain its daily use. We also show you how you can
customize @t{mu4e} for your needs.
At the end of the manual, there are some example configurations, to get up to
speed quickly - @ref{Example configurations}. There's also a section of
@ref{FAQ}, which should help you with some common questions.
At the end of the manual, there are some example configurations, to get you up
to speed quickly: @ref{Example configurations}. There's also an @ref{FAQ},
which should help you with some common questions.
@menu
* Introduction:: How it all began
@ -176,24 +177,26 @@ efficiently as possible.
If @t{mu4e} looks like something for you, give it a shot! We've been trying
hard to make it as easy as possible to set up and use; and while you can use
elisp is various places to augment @t{mu4e}, programming is by no mean required.
elisp in various places to augment @t{mu4e}, a lot of knowledge about
programming or elisp shouldn't be required.
When you take @t{mu4e} into use, it's a good idea to subscribe to the
@t{mu}/@t{mu4e}-mailing
list@footnote{@url{http://groups.google.com/group/mu-discuss}}. If you have
suggestions for improvements or bug reports, please use the GitHub issues
list@footnote{@url{https://github.com/djcb/mu/issues}}. In bug reports, please
clearly specify the versions of @t{mu}/@t{mu4e} and @command{emacs} you are
using, as well as any other relevant details. If you are new to all this, the
somewhat paternalistic @emph{``How to ask questions the smart
way''}@footnote{@url{http://www.catb.org/esr/faqs/smart-questions.html}} can be
a good read.
list@footnote{@url{http://groups.google.com/group/mu-discuss}}.
If you have suggestions for improvements or bug reports, please use the GitHub
issues list@footnote{@url{https://github.com/djcb/mu/issues}}. In bug reports,
please clearly specify the versions of @t{mu}/@t{mu4e} and @command{emacs} you
are using, as well as any other relevant details. If you are new to all this,
the somewhat paternalistic @emph{``How to ask questions the smart
way''}@footnote{@url{http://www.catb.org/esr/faqs/smart-questions.html}} can
be a good read.
@node Getting started
@chapter Getting started
In this chapter, we go through the installation of @t{mu4e} and its basic
setup. After we have succeeded in @ref{Getting mail}, and @ref{Indexing your
setup. After we have succeeded in @ref{Getting mail}, and @pxref{Indexing your
messages}, we discuss @ref{Basic configuration}.
After these steps, @t{mu4e} should be ready to go!
@ -218,10 +221,16 @@ After these steps, @t{mu4e} should be ready to go!
systems, including many Linux distributions, MacOS and
FreeBSD. @command{emacs} 23 or 24 is required, as well as
Xapian@footnote{@url{http://xapian.org/}} and
GMime@footnote{@url{http://spruce.sourceforge.net/gmime/}}. If you intend to
compile yourself, you need to have the typical development tools, such as C
and C++ compilers (both @command{gcc} and @command{clang} should work) and
@command{make}.
GMime@footnote{@url{http://spruce.sourceforge.net/gmime/}}.
@t{mu} has optional support the Guile 2.x (Scheme) programming language. There
are also some GUI-tools, which require GTK+ and Webkit; either the GTK+2 or
GTK+3-versions.
If you intend to compile it yourself, you need to have the typical development
tools, such as C and C++ compilers (both @command{gcc} and @command{clang}
should work), GNU Autotools and @command{make}, and (if you use them) the
development packages for GTK+, Webkit and Guile.
@node Installation
@section Installation
@ -1536,7 +1545,10 @@ date:today..now
# get all messages we got in the last two weeks regarding emacs:
date:2w..now emacs
# get mails with a subject soccer, Socrates, society...:
# get messages from the the Mu mailing list:
mu find list:mu-discuss.googlegroups.com
# get messages with a subject soccer, Socrates, society...:
subject:soc*
# note: the '*' wildcard can only appear as the term's rightmost character
@ -1549,7 +1561,8 @@ mime:application/pdf
# get all messages with image attachments:
mime:image/*
# note: the '*' wildcard can only appear as the term's rightmost character
# note: the '*' wildcard can only appear as the term's @emph{rightmost}
# character
@end verbatim
@node Bookmarks
@ -2914,6 +2927,19 @@ messages}.
like Gmail does?} Yes -- see @ref{Including related messages}.
@item @emph{There seem to be a lot of duplicate messages -- how can I get rid
of them?} See @ref{Skipping duplicates}.
@item @emph{Some messages are almost unreadable in emacs - can I view them in
an external web browser?} Indeed, airlines often send messages that heavily
depend on html and are hard to digest inside emacs. Fortunately, there's an
@emph{action} (@ref{Adding an action in the message view}) defined for
this. Simply add to your configuration:
@lisp
(add-to-list 'mu4e-view-actions
'("ViewInBrowser" . mu4e-action-view-in-browser) t)
@end lisp
Now, when viewing such a difficult message, type @kbd{aV}, and the message
opens inside a webbrowser. You can influence the browser with
@code{browse-url-generic-program}.
@end enumerate
@node Writing messages
@ -2948,6 +2974,17 @@ messages stay around. How can I get rid of those?}
@lisp
(setq message-kill-buffer-on-exit t)
@end lisp
@item @emph{Sending big messages is slow and blocks emacs - what can I do
about it?} For this, there's @url{https://github.com/jwiegley/emacs-async}
(also available from the Emacs package repository); add the following snippet
to your configuration:
@lisp
(require 'smtpmail-async)
(setq
send-mail-function 'async-smtpmail-send-it
message-send-mail-function 'async-smtpmail-send-it)
@end lisp
With this, messages are sent using background emacs-instance.
@end enumerate
@node Known issues

View File

@ -1,5 +1,5 @@
/*
** Copyright (C) 2011-2012 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
** Copyright (C) 2011-2013 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** This program is free software; you can redistribute it and/or modify it
** under the terms of the GNU General Public License as published by the
@ -252,8 +252,8 @@ each_part (MuMsg *msg, MuMsgPart *part, CBData *cbdata)
pixbuf = mu_widget_util_get_icon_pixbuf_for_content_type (ctype, 16);
if (!pixbuf) {
g_warning ("%s: could not get icon pixbuf for '%s'",
__FUNCTION__, ctype);
g_debug ("%s: could not get icon pixbuf for '%s'",
__FUNCTION__, ctype);
pixbuf = mu_widget_util_get_icon_pixbuf_for_content_type
("application/octet-stream", 16);
}

View File

@ -39,27 +39,18 @@ enum {
};
struct _MuMsgHeaderViewPrivate {
GtkWidget *_table;
GtkWidget *_grid;
};
#define MU_MSG_HEADER_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
MU_TYPE_MSG_HEADER_VIEW, \
MuMsgHeaderViewPrivate))
/* globals */
#ifdef HAVE_GTK3
static GtkBoxClass *parent_class = NULL;
#else
static GtkVBoxClass *parent_class = NULL;
#endif /*!HAVE_GTK3*/
/* uncomment the following if you have defined any signals */
/* static guint signals[LAST_SIGNAL] = {0}; */
#ifdef HAVE_GTK3
G_DEFINE_TYPE (MuMsgHeaderView, mu_msg_header_view, GTK_TYPE_BOX);
#else
G_DEFINE_TYPE (MuMsgHeaderView, mu_msg_header_view, GTK_TYPE_VBOX);
#endif /*!HAVE_GTK3*/
static void
@ -85,13 +76,9 @@ static void
mu_msg_header_view_init (MuMsgHeaderView *obj)
{
/* #ifdef HAVE_GTK3 */
/* static GtkBoxClass *parent_class = NULL; */
/* #endif /\*!HAVE_GTK3*\/ */
obj->_priv = MU_MSG_HEADER_VIEW_GET_PRIVATE(obj);
obj->_priv->_table = NULL;
obj->_priv->_grid = NULL;
}
static void
@ -129,7 +116,7 @@ get_label (const gchar *txt, gboolean istitle)
}
static gboolean
add_row (GtkWidget *table, guint row, const char* fieldname, const char *value,
add_row (GtkWidget *grid, guint row, const char* fieldname, const char *value,
gboolean showempty)
{
GtkWidget *label, *al;
@ -137,52 +124,49 @@ add_row (GtkWidget *table, guint row, const char* fieldname, const char *value,
if (!value && !showempty)
return FALSE;
gtk_grid_insert_row (GTK_GRID(grid), row);
label = get_label (fieldname, TRUE);
al = gtk_alignment_new (0.0, 0.0, 0.0, 0.0);
gtk_container_add (GTK_CONTAINER (al), label);
gtk_table_attach (
GTK_TABLE(table), al,
0, 1, row, row + 1, GTK_FILL, 0, 0, 0);
gtk_grid_attach (GTK_GRID(grid), al, 0, row, 1, 1);
al = gtk_alignment_new (0.0, 1.0, 0.0, 0.0);
label = get_label (value, FALSE);
gtk_container_add (GTK_CONTAINER (al), label);
gtk_table_attach (
GTK_TABLE(table), al, 1, 2, row, row + 1, GTK_FILL,
0, 0, 0);
gtk_grid_attach (GTK_GRID(grid), al, 1, row, 1, 1);
return TRUE;
}
GtkWidget *
get_table (MuMsg *msg)
get_grid (MuMsg *msg)
{
GtkWidget *table;
GtkWidget *grid;
int row;
row = 0;
grid = gtk_grid_new (); /* 5 2 */
table = gtk_table_new (5, 2, FALSE);
gtk_grid_insert_column (GTK_GRID(grid), 0);
gtk_grid_insert_column (GTK_GRID(grid), 1);
if (add_row (table, row, "From", mu_msg_get_from (msg), TRUE))
if (add_row (grid, row, "From", mu_msg_get_from (msg), TRUE))
++row;
if (add_row (table, row, "To", mu_msg_get_to (msg), FALSE))
if (add_row (grid, row, "To", mu_msg_get_to (msg), FALSE))
++row;
if (add_row (table, row, "Cc", mu_msg_get_cc (msg), FALSE))
if (add_row (grid, row, "Cc", mu_msg_get_cc (msg), FALSE))
++row;
if (add_row (table, row, "Subject", mu_msg_get_subject (msg), TRUE))
if (add_row (grid, row, "Subject", mu_msg_get_subject (msg), TRUE))
++row;
if (add_row (table, row, "Date", mu_date_str_s
if (add_row (grid, row, "Date", mu_date_str_s
("%c", mu_msg_get_date (msg)),TRUE))
++row;
gtk_table_resize (GTK_TABLE(table), row, 2);
return table;
return grid;
}
void
@ -190,15 +174,15 @@ mu_msg_header_view_set_message (MuMsgHeaderView *self, MuMsg *msg)
{
g_return_if_fail (MU_IS_MSG_HEADER_VIEW(self));
if (self->_priv->_table) {
gtk_container_remove (GTK_CONTAINER(self), self->_priv->_table);
self->_priv->_table = NULL;
if (self->_priv->_grid) {
gtk_container_remove (GTK_CONTAINER(self), self->_priv->_grid);
self->_priv->_grid = NULL;
}
if (msg) {
self->_priv->_table = get_table (msg);
gtk_box_pack_start (GTK_BOX(self), self->_priv->_table,
self->_priv->_grid = get_grid (msg);
gtk_box_pack_start (GTK_BOX(self), self->_priv->_grid,
TRUE, TRUE, 0);
gtk_widget_show_all (self->_priv->_table);
gtk_widget_show_all (self->_priv->_grid);
}
}

View File

@ -42,24 +42,14 @@ typedef struct _MuMsgHeaderViewClass MuMsgHeaderViewClass;
typedef struct _MuMsgHeaderViewPrivate MuMsgHeaderViewPrivate;
struct _MuMsgHeaderView {
#ifdef HAVE_GTK3
GtkBox parent;
#else
GtkVBox parent;
#endif /*!HAVE_GTK3*/
/* insert public members, if any */
/* private */
MuMsgHeaderViewPrivate *_priv;
};
struct _MuMsgHeaderViewClass {
#ifdef HAVE_GTK3
GtkBoxClass parent_class;
#else
GtkVBoxClass parent_class;
#endif /*!HAVE_GTK3*/
/* insert signal callback declarations, e.g. */
/* void (* my_event) (MuMsgHeaderView* obj); */
};

View File

@ -48,24 +48,12 @@ struct _MuMsgViewPrivate {
MU_TYPE_MSG_VIEW, \
MuMsgViewPrivate))
/* globals */
#ifdef HAVE_GTK3
static GtkBoxClass *parent_class = NULL;
#else
static GtkVBoxClass *parent_class = NULL;
#endif /*!HAVE_GTK3*/
/* uncomment the following if you have defined any signals */
/* static guint signals[LAST_SIGNAL] = {0}; */
#ifdef HAVE_GTK3
G_DEFINE_TYPE (MuMsgView, mu_msg_view, GTK_TYPE_BOX);
#else
G_DEFINE_TYPE (MuMsgView, mu_msg_view, GTK_TYPE_VBOX);
#endif /*HAVE_GTK3*/
static void
set_message (MuMsgView *self, MuMsg *msg)
@ -154,11 +142,12 @@ on_attach_activated (GtkWidget *w, guint partnum, MuMsg *msg)
static void
mu_msg_view_init (MuMsgView *self)
{
self->_priv = MU_MSG_VIEW_GET_PRIVATE(self);
gtk_orientable_set_orientation (GTK_ORIENTABLE(self),
GTK_ORIENTATION_VERTICAL);
self->_priv = MU_MSG_VIEW_GET_PRIVATE(self);
self->_priv->_msg = NULL;
self->_priv->_headers = mu_msg_header_view_new ();
self->_priv->_attach = mu_msg_attach_view_new ();
self->_priv->_attachexpander = gtk_expander_new_with_mnemonic
("_Attachments");
@ -178,6 +167,10 @@ mu_msg_view_init (MuMsgView *self)
FALSE, FALSE, 2);
gtk_box_pack_start (GTK_BOX(self), self->_priv->_attachexpander,
FALSE, FALSE, 2);
gtk_box_pack_start (GTK_BOX(self),
gtk_separator_new(GTK_ORIENTATION_HORIZONTAL),
TRUE,TRUE,0);
gtk_box_pack_start (GTK_BOX(self), self->_priv->_body,
TRUE, TRUE, 2);
}

View File

@ -42,22 +42,13 @@ typedef struct _MuMsgViewClass MuMsgViewClass;
typedef struct _MuMsgViewPrivate MuMsgViewPrivate;
struct _MuMsgView {
#ifdef HAVE_GTK3
GtkBox parent;
#else
GtkVBox parent;
#endif /*!HAVE_GTK3*/
/* private */
MuMsgViewPrivate *_priv;
};
struct _MuMsgViewClass {
#ifdef HAVE_GTK3
GtkBoxClass parent_class;
#else
GtkVBoxClass parent_class;
#endif /*!HAVE_GTK3*/
/* void (* my_event) (MuMsgView* obj); */
};

View File

@ -46,13 +46,8 @@ struct _MugMsgViewPrivate {
#define MUG_MSG_VIEW_GET_PRIVATE(o)(G_TYPE_INSTANCE_GET_PRIVATE((o),MUG_TYPE_MSG_VIEW, MugMsgViewPrivate))
/* globals */
#ifdef HAVE_GTK3
static GtkBoxClass *parent_class = NULL;
G_DEFINE_TYPE (MugMsgView, mug_msg_view, GTK_TYPE_BOX);
#else
static GtkVBoxClass *parent_class = NULL;
G_DEFINE_TYPE (MugMsgView, mug_msg_view, GTK_TYPE_VBOX);
#endif /*!HAVE_GTK3*/
/* uncomment the following if you have defined any signals */
/* static guint signals[LAST_SIGNAL] = {0}; */

View File

@ -1,5 +1,5 @@
/*
** Copyright (C) 2010 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
** Copyright (C) 2010-2013 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** This program is free software; you can redistribute it and/or modify it
** under the terms of the GNU General Public License as published by the
@ -23,9 +23,6 @@
#include <gtk/gtk.h>
/* other include files */
G_BEGIN_DECLS
/* convenience macros */
#define MUG_TYPE_MSG_VIEW (mug_msg_view_get_type())
@ -38,20 +35,11 @@ typedef struct _MugMsgView MugMsgView;
typedef struct _MugMsgViewClass MugMsgViewClass;
struct _MugMsgView {
#ifdef HAVE_GTK3
GtkBox parent;
#else
GtkVBox parent;
#endif /*!HAVE_GTK3*/
};
struct _MugMsgViewClass {
#ifdef HAVE_GTK3
GtkBoxClass parent_class;
#else
GtkVBoxClass parent_class;
#endif /*!HAVE_GTK3*/
/* insert signal callback declarations, e.g. */
/* void (* my_event) (MugMsg* obj); */
};
@ -66,4 +54,5 @@ gboolean mug_msg_view_set_msg (MugMsgView * self, const char *msgpath);
void mug_msg_view_set_note (MugMsgView * self, const char* html);
G_END_DECLS
#endif /* __MUG_MSG_VIEW_H__ */
#endif /* __MUG_MSG_VIEW_H__ */

View File

@ -29,13 +29,7 @@ static GtkContainerClass *parent_class = NULL;
static guint signals[LAST_SIGNAL] = { 0 };
#ifdef HAVE_GTK3
G_DEFINE_TYPE (MugQueryBar, mug_query_bar, GTK_TYPE_BOX);
#else
G_DEFINE_TYPE (MugQueryBar, mug_query_bar, GTK_TYPE_HBOX);
#endif /*!HAVE_GTK3*/
static void
mug_query_bar_class_init (MugQueryBarClass * klass)

View File

@ -22,22 +22,12 @@ typedef struct _MugQueryBar MugQueryBar;
typedef struct _MugQueryBarClass MugQueryBarClass;
struct _MugQueryBar {
#ifdef HAVE_GTK3
GtkBox parent;
#else
GtkHBox parent;
#endif /*!HAVE_GTK3*/
};
struct _MugQueryBarClass {
#ifdef HAVE_GTK3
GtkBox parent;
GtkBoxClass parent_class;
#else
GtkHBox parent;
GtkHBoxClass parent_class;
#endif /*!HAVE_GTK3*/
/* insert signal callback declarations, e.g. */
void (*query_changed) (MugQueryBar * obj, const char *query);
};

View File

@ -49,13 +49,8 @@ struct _MugShortcutsPrivate {
static guint signals[LAST_SIGNAL] = { 0 };
#ifdef HAVE_GTK3
static GtkBoxClass *parent_class = NULL;
G_DEFINE_TYPE (MugShortcuts, mug_shortcuts, GTK_TYPE_BOX);
#else
static GtkVBoxClass *parent_class = NULL;
G_DEFINE_TYPE (MugShortcuts, mug_shortcuts, GTK_TYPE_VBOX);
#endif /*!HAVE_GTK3*/
static void
mug_shortcuts_class_init (MugShortcutsClass * klass)
@ -87,12 +82,7 @@ static void
mug_shortcuts_init (MugShortcuts * obj)
{
obj->_priv = MUG_SHORTCUTS_GET_PRIVATE (obj);
#ifdef HAVE_GTK3
obj->_priv->_bbox = gtk_button_box_new (GTK_ORIENTATION_VERTICAL);
#else
obj->_priv->_bbox = gtk_vbutton_box_new ();
#endif /*!HAVE_GTK3*/
gtk_button_box_set_layout (GTK_BUTTON_BOX (obj->_priv->_bbox),
GTK_BUTTONBOX_START);

View File

@ -41,30 +41,18 @@ typedef struct _MugShortcutsClass MugShortcutsClass;
typedef struct _MugShortcutsPrivate MugShortcutsPrivate;
struct _MugShortcuts {
#ifdef HAVE_GTK3
GtkBox parent;
#else
GtkVBox parent;
#endif /*!HAVE_GTK3*/
/* private */
MugShortcutsPrivate *_priv;
};
struct _MugShortcutsClass {
#ifdef HAVE_GTK3
GtkBoxClass parent_class;
#else
GtkVBoxClass parent_class;
#endif /*!HAVE_GTK3*/
void (*clicked) (MugShortcuts * obj, const char *query);
};
/* member functions */
GType
mug_shortcuts_get_type (void)
G_GNUC_CONST;
GType mug_shortcuts_get_type (void) G_GNUC_CONST;
/* parameter-less _new function (constructor) */
/* if this is a kind of GtkWidget, it should probably return at GtkWidget* */
@ -76,4 +64,5 @@ mug_shortcuts_new (const char *bmpath);
/* gboolean mug_shortcuts_has_foo (MugShortcuts *self, gint value); */
G_END_DECLS
#endif /* __MUG_SHORTCUTS_H__ */
#endif /* __MUG_SHORTCUTS_H__ */

View File

@ -263,14 +263,8 @@ mug_query_area (MugData * mugdata)
{
GtkWidget *queryarea, *paned, *scrolled;
#ifdef HAVE_GTK3
queryarea = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
paned = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
#else
queryarea = gtk_vbox_new (FALSE, 2);
paned = gtk_vpaned_new ();
#endif /*!HAVE_GTK3*/
mugdata->mlist = mug_msg_list_view_new
(mu_runtime_path(MU_RUNTIME_PATH_XAPIANDB));
@ -310,11 +304,7 @@ mug_main_area (MugData * mugdata)
{
GtkWidget *mainarea, *w;
#ifdef HAVE_GTK3
mainarea = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
#else
mainarea = gtk_hbox_new (FALSE, 5);
#endif /*!HAVE_GTK3*/
w = mug_shortcuts_bar (mugdata);
gtk_box_pack_start (GTK_BOX (mainarea), w, FALSE, FALSE, 0);
@ -335,11 +325,7 @@ mug_shell (MugData * mugdata)
mugdata->win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (mugdata->win), "Mug Mail Search");
#ifdef HAVE_GTK3
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
#else
vbox = gtk_vbox_new (FALSE, 2);
#endif /*!HAVE_GTK3*/
mugdata->toolbar = mug_toolbar (mugdata);
gtk_box_pack_start (GTK_BOX (vbox), mugdata->toolbar, FALSE, FALSE, 2);
@ -370,11 +356,6 @@ mug_shell (MugData * mugdata)
static gint
on_focus_query_bar (GtkWidget* ignored, GdkEventKey *event, MugData* mugdata)
{
/* gtk2: GDK_Escape; gtk3: GDK_Key_Escape */
#ifndef GDK_KEY_Escape
#define GDK_KEY_Escape GDK_Escape
#endif /* GDK_KEY_Escape */
if (event->type==GDK_KEY_RELEASE && event->keyval==GDK_KEY_Escape) {
mug_query_bar_grab_focus (MUG_QUERY_BAR (mugdata->querybar));
return 1;