From a26811626d94ad7fa4c4dc8b4a26722e67f133d5 Mon Sep 17 00:00:00 2001 From: opfez Date: Mon, 18 Jul 2022 12:11:38 +0200 Subject: [PATCH] mu4e --- elisp/mu4e/Makefile.am | 66 + elisp/mu4e/Makefile.in | 1223 +++++++ elisp/mu4e/TODO | 19 + elisp/mu4e/fdl.texi | 451 +++ elisp/mu4e/mu4e-about.org | 15 + elisp/mu4e/mu4e-actions.el | 253 ++ elisp/mu4e/mu4e-compose.el | 1114 ++++++ elisp/mu4e/mu4e-context.el | 183 + elisp/mu4e/mu4e-contrib.el | 224 ++ elisp/mu4e/mu4e-draft.el | 604 ++++ elisp/mu4e/mu4e-headers.el | 2002 +++++++++++ elisp/mu4e/mu4e-icalendar.el | 211 ++ elisp/mu4e/mu4e-lists.el | 102 + elisp/mu4e/mu4e-main.el | 387 ++ elisp/mu4e/mu4e-mark.el | 470 +++ elisp/mu4e/mu4e-message.el | 364 ++ elisp/mu4e/mu4e-meta.el | 11 + elisp/mu4e/mu4e-meta.el.in | 11 + elisp/mu4e/mu4e-org.el | 127 + elisp/mu4e/mu4e-proc.el | 501 +++ elisp/mu4e/mu4e-speedbar.el | 134 + elisp/mu4e/mu4e-utils.el | 1381 ++++++++ elisp/mu4e/mu4e-vars.el | 1202 +++++++ elisp/mu4e/mu4e-view-common.el | 642 ++++ elisp/mu4e/mu4e-view-gnus.el | 625 ++++ elisp/mu4e/mu4e-view-old.el | 1097 ++++++ elisp/mu4e/mu4e-view.el | 69 + elisp/mu4e/mu4e.el | 67 + elisp/mu4e/mu4e.info | 5823 +++++++++++++++++++++++++++++++ elisp/mu4e/mu4e.texi | 5101 +++++++++++++++++++++++++++ elisp/mu4e/obsolete/org-mu4e.el | 234 ++ elisp/mu4e/stamp-vti | 4 + elisp/mu4e/version.texi | 4 + 33 files changed, 24721 insertions(+) create mode 100644 elisp/mu4e/Makefile.am create mode 100644 elisp/mu4e/Makefile.in create mode 100644 elisp/mu4e/TODO create mode 100644 elisp/mu4e/fdl.texi create mode 100644 elisp/mu4e/mu4e-about.org create mode 100644 elisp/mu4e/mu4e-actions.el create mode 100644 elisp/mu4e/mu4e-compose.el create mode 100644 elisp/mu4e/mu4e-context.el create mode 100644 elisp/mu4e/mu4e-contrib.el create mode 100644 elisp/mu4e/mu4e-draft.el create mode 100644 elisp/mu4e/mu4e-headers.el create mode 100644 elisp/mu4e/mu4e-icalendar.el create mode 100644 elisp/mu4e/mu4e-lists.el create mode 100644 elisp/mu4e/mu4e-main.el create mode 100644 elisp/mu4e/mu4e-mark.el create mode 100644 elisp/mu4e/mu4e-message.el create mode 100644 elisp/mu4e/mu4e-meta.el create mode 100644 elisp/mu4e/mu4e-meta.el.in create mode 100644 elisp/mu4e/mu4e-org.el create mode 100644 elisp/mu4e/mu4e-proc.el create mode 100644 elisp/mu4e/mu4e-speedbar.el create mode 100644 elisp/mu4e/mu4e-utils.el create mode 100644 elisp/mu4e/mu4e-vars.el create mode 100644 elisp/mu4e/mu4e-view-common.el create mode 100644 elisp/mu4e/mu4e-view-gnus.el create mode 100644 elisp/mu4e/mu4e-view-old.el create mode 100644 elisp/mu4e/mu4e-view.el create mode 100644 elisp/mu4e/mu4e.el create mode 100644 elisp/mu4e/mu4e.info create mode 100644 elisp/mu4e/mu4e.texi create mode 100644 elisp/mu4e/obsolete/org-mu4e.el create mode 100644 elisp/mu4e/stamp-vti create mode 100644 elisp/mu4e/version.texi diff --git a/elisp/mu4e/Makefile.am b/elisp/mu4e/Makefile.am new file mode 100644 index 0000000..3239da6 --- /dev/null +++ b/elisp/mu4e/Makefile.am @@ -0,0 +1,66 @@ +## Copyright (C) 2008-2017 Dirk-Jan C. Binnema +## +## 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 Free Software Foundation; either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software Foundation, +## Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +include $(top_srcdir)/gtest.mk + +SUBDIRS= + +info_TEXINFOS=mu4e.texi +mu4e_TEXINFOS=fdl.texi + +dist_lisp_LISP= \ + mu4e-actions.el \ + mu4e-compose.el \ + mu4e-context.el \ + mu4e-contrib.el \ + mu4e-draft.el \ + mu4e-headers.el \ + mu4e-icalendar.el \ + mu4e-lists.el \ + mu4e-main.el \ + mu4e-mark.el \ + mu4e-message.el \ + mu4e-meta.el \ + mu4e-org.el \ + mu4e-proc.el \ + mu4e-speedbar.el \ + mu4e-utils.el \ + mu4e-vars.el \ + mu4e-view.el \ + mu4e-view-common.el \ + mu4e-view-gnus.el \ + mu4e-view-old.el \ + mu4e.el \ + obsolete/org-mu4e.el + + +EXTRA_DIST= \ + mu4e-about.org + +CLEANFILES= \ + *.elc + +doc_DATA = \ + mu4e-about.org + +## +## Change as needed. +## +BUILDPATH=mu4e +TEXINFO_CSS_PATH=~/Sources/ext/texinfo-css +fancyhtml: + mkdir -p $(BUILDPATH) ; cp -R $(TEXINFO_CSS_PATH)/static $(BUILDPATH) + makeinfo --html --css-ref=static/css/texinfo-klare.css -o $(BUILDPATH) mu4e.texi diff --git a/elisp/mu4e/Makefile.in b/elisp/mu4e/Makefile.in new file mode 100644 index 0000000..f3eb6a7 --- /dev/null +++ b/elisp/mu4e/Makefile.in @@ -0,0 +1,1223 @@ +# Makefile.in generated by automake 1.16.2 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2020 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = mu4e +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_ac_append_to_file.m4 \ + $(top_srcdir)/m4/ax_ac_print_to_file.m4 \ + $(top_srcdir)/m4/ax_add_am_macro_static.m4 \ + $(top_srcdir)/m4/ax_am_macros_static.m4 \ + $(top_srcdir)/m4/ax_append_compile_flags.m4 \ + $(top_srcdir)/m4/ax_append_flag.m4 \ + $(top_srcdir)/m4/ax_check_compile_flag.m4 \ + $(top_srcdir)/m4/ax_check_gnu_make.m4 \ + $(top_srcdir)/m4/ax_code_coverage.m4 \ + $(top_srcdir)/m4/ax_compiler_flags_cxxflags.m4 \ + $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/m4/ax_cxx_compile_stdcxx_14.m4 \ + $(top_srcdir)/m4/ax_file_escapes.m4 \ + $(top_srcdir)/m4/ax_lib_readline.m4 \ + $(top_srcdir)/m4/ax_require_defined.m4 \ + $(top_srcdir)/m4/ax_valgrind_check.m4 \ + $(top_srcdir)/m4/guile.m4 $(top_srcdir)/m4/host-cpu-c-abi.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/version.texi \ + $(srcdir)/stamp-vti $(dist_lisp_LISP) $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = mu4e-meta.el +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +AM_V_DVIPS = $(am__v_DVIPS_@AM_V@) +am__v_DVIPS_ = $(am__v_DVIPS_@AM_DEFAULT_V@) +am__v_DVIPS_0 = @echo " DVIPS " $@; +am__v_DVIPS_1 = +AM_V_MAKEINFO = $(am__v_MAKEINFO_@AM_V@) +am__v_MAKEINFO_ = $(am__v_MAKEINFO_@AM_DEFAULT_V@) +am__v_MAKEINFO_0 = @echo " MAKEINFO" $@; +am__v_MAKEINFO_1 = +AM_V_INFOHTML = $(am__v_INFOHTML_@AM_V@) +am__v_INFOHTML_ = $(am__v_INFOHTML_@AM_DEFAULT_V@) +am__v_INFOHTML_0 = @echo " INFOHTML" $@; +am__v_INFOHTML_1 = +AM_V_TEXI2DVI = $(am__v_TEXI2DVI_@AM_V@) +am__v_TEXI2DVI_ = $(am__v_TEXI2DVI_@AM_DEFAULT_V@) +am__v_TEXI2DVI_0 = @echo " TEXI2DVI" $@; +am__v_TEXI2DVI_1 = +AM_V_TEXI2PDF = $(am__v_TEXI2PDF_@AM_V@) +am__v_TEXI2PDF_ = $(am__v_TEXI2PDF_@AM_DEFAULT_V@) +am__v_TEXI2PDF_0 = @echo " TEXI2PDF" $@; +am__v_TEXI2PDF_1 = +AM_V_texinfo = $(am__v_texinfo_@AM_V@) +am__v_texinfo_ = $(am__v_texinfo_@AM_DEFAULT_V@) +am__v_texinfo_0 = -q +am__v_texinfo_1 = +AM_V_texidevnull = $(am__v_texidevnull_@AM_V@) +am__v_texidevnull_ = $(am__v_texidevnull_@AM_DEFAULT_V@) +am__v_texidevnull_0 = > /dev/null +am__v_texidevnull_1 = +INFO_DEPS = $(srcdir)/mu4e.info +TEXINFO_TEX = $(top_srcdir)/build-aux/texinfo.tex +am__TEXINFO_TEX_DIR = $(top_srcdir)/build-aux +DVIS = mu4e.dvi +PDFS = mu4e.pdf +PSS = mu4e.ps +HTMLS = mu4e.html +TEXINFOS = mu4e.texi +TEXI2DVI = texi2dvi +TEXI2PDF = $(TEXI2DVI) --pdf --batch +MAKEINFOHTML = $(MAKEINFO) --html +AM_MAKEINFOHTMLFLAGS = $(AM_MAKEINFOFLAGS) +DVIPS = dvips +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__installdirs = "$(DESTDIR)$(infodir)" "$(DESTDIR)$(lispdir)" \ + "$(DESTDIR)$(docdir)" +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__emacs_byte_compile_setup = \ + (if (boundp (quote byte-compile-dest-file-function)) \ + (setq byte-compile-dest-file-function (lambda (_) "$@")) \ + (defun byte-compile-dest-file (_) "$@") \ + ) +dist_lispLISP_INSTALL = $(INSTALL_DATA) +LISP = $(dist_lisp_LISP) +am__ELFILES = mu4e-actions.el mu4e-compose.el mu4e-context.el \ + mu4e-contrib.el mu4e-draft.el mu4e-headers.el \ + mu4e-icalendar.el mu4e-lists.el mu4e-main.el mu4e-mark.el \ + mu4e-message.el mu4e-meta.el mu4e-org.el mu4e-proc.el \ + mu4e-speedbar.el mu4e-utils.el mu4e-vars.el \ + mu4e-view-common.el mu4e-view-gnus.el mu4e-view-old.el \ + mu4e-view.el mu4e.el obsolete/org-mu4e.el +am__ELCFILES = $(am__ELFILES:.el=.elc) +ELCFILES = $(LISP:.el=.elc) +DATA = $(doc_DATA) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__extra_recursive_targets = check-valgrind-recursive \ + check-valgrind-memcheck-recursive \ + check-valgrind-helgrind-recursive check-valgrind-drd-recursive \ + check-valgrind-sgcheck-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(mu4e_TEXINFOS) $(srcdir)/Makefile.in \ + $(srcdir)/mu4e-meta.el.in $(top_srcdir)/build-aux/mdate-sh \ + $(top_srcdir)/build-aux/texinfo.tex $(top_srcdir)/gtest.mk \ + TODO +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ASAN_CFLAGS = @ASAN_CFLAGS@ +ASAN_CXXFLAGS = @ASAN_CXXFLAGS@ +ASAN_LDFLAGS = @ASAN_LDFLAGS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@ +CODE_COVERAGE_CPPFLAGS = @CODE_COVERAGE_CPPFLAGS@ +CODE_COVERAGE_CXXFLAGS = @CODE_COVERAGE_CXXFLAGS@ +CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@ +CODE_COVERAGE_LIBS = @CODE_COVERAGE_LIBS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EMACS = @EMACS@ +EMACSLOADPATH = @EMACSLOADPATH@ +ENABLE_VALGRIND_drd = @ENABLE_VALGRIND_drd@ +ENABLE_VALGRIND_helgrind = @ENABLE_VALGRIND_helgrind@ +ENABLE_VALGRIND_memcheck = @ENABLE_VALGRIND_memcheck@ +ENABLE_VALGRIND_sgcheck = @ENABLE_VALGRIND_sgcheck@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCOV = @GCOV@ +GENHTML = @GENHTML@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GMIME_CFLAGS = @GMIME_CFLAGS@ +GMIME_LIBS = @GMIME_LIBS@ +GREP = @GREP@ +GTK_CFLAGS = @GTK_CFLAGS@ +GTK_LIBS = @GTK_LIBS@ +GUILD = @GUILD@ +GUILE = @GUILE@ +GUILE_CFLAGS = @GUILE_CFLAGS@ +GUILE_CONFIG = @GUILE_CONFIG@ +GUILE_EFFECTIVE_VERSION = @GUILE_EFFECTIVE_VERSION@ +GUILE_LDFLAGS = @GUILE_LDFLAGS@ +GUILE_LIBS = @GUILE_LIBS@ +GUILE_LTLIBS = @GUILE_LTLIBS@ +GUILE_SNARF = @GUILE_SNARF@ +GUILE_TOOLS = @GUILE_TOOLS@ +HAVE_CXX14 = @HAVE_CXX14@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MU_DOC_DIR = @MU_DOC_DIR@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +READLINE_LIBS = @READLINE_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SORT = @SORT@ +STRIP = @STRIP@ +VALGRIND = @VALGRIND@ +VALGRIND_ENABLED = @VALGRIND_ENABLED@ +VERSION = @VERSION@ +WARN_CXXFLAGS = @WARN_CXXFLAGS@ +WEBKIT_CFLAGS = @WEBKIT_CFLAGS@ +WEBKIT_LIBS = @WEBKIT_LIBS@ +XAPIAN_CFLAGS = @XAPIAN_CFLAGS@ +XAPIAN_CONFIG = @XAPIAN_CONFIG@ +XAPIAN_CXXFLAGS = @XAPIAN_CXXFLAGS@ +XAPIAN_LIBS = @XAPIAN_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +have_makeinfo = @have_makeinfo@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +ifGNUmake = @ifGNUmake@ +ifnGNUmake = @ifnGNUmake@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +lispdir = @lispdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +valgrind_enabled_tools = @valgrind_enabled_tools@ +valgrind_tools = @valgrind_tools@ +TEST_PROGS = +SUBDIRS = +info_TEXINFOS = mu4e.texi +mu4e_TEXINFOS = fdl.texi +dist_lisp_LISP = \ + mu4e-actions.el \ + mu4e-compose.el \ + mu4e-context.el \ + mu4e-contrib.el \ + mu4e-draft.el \ + mu4e-headers.el \ + mu4e-icalendar.el \ + mu4e-lists.el \ + mu4e-main.el \ + mu4e-mark.el \ + mu4e-message.el \ + mu4e-meta.el \ + mu4e-org.el \ + mu4e-proc.el \ + mu4e-speedbar.el \ + mu4e-utils.el \ + mu4e-vars.el \ + mu4e-view.el \ + mu4e-view-common.el \ + mu4e-view-gnus.el \ + mu4e-view-old.el \ + mu4e.el \ + obsolete/org-mu4e.el + +EXTRA_DIST = \ + mu4e-about.org + +CLEANFILES = \ + *.elc + +doc_DATA = \ + mu4e-about.org + +BUILDPATH = mu4e +TEXINFO_CSS_PATH = ~/Sources/ext/texinfo-css +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .dvi .el .elc .html .info .pdf .ps .texi +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/gtest.mk $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign mu4e/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign mu4e/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; +$(top_srcdir)/gtest.mk $(am__empty): + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +mu4e-meta.el: $(top_builddir)/config.status $(srcdir)/mu4e-meta.el.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +.texi.info: + $(AM_V_MAKEINFO)restore=: && backupdir="$(am__leading_dot)am$$$$" && \ + am__cwd=`pwd` && $(am__cd) $(srcdir) && \ + rm -rf $$backupdir && mkdir $$backupdir && \ + if ($(MAKEINFO) --version) >/dev/null 2>&1; then \ + for f in $@ $@-[0-9] $@-[0-9][0-9] $(@:.info=).i[0-9] $(@:.info=).i[0-9][0-9]; do \ + if test -f $$f; then mv $$f $$backupdir; restore=mv; else :; fi; \ + done; \ + else :; fi && \ + cd "$$am__cwd"; \ + if $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ + -o $@ $<; \ + then \ + rc=0; \ + $(am__cd) $(srcdir); \ + else \ + rc=$$?; \ + $(am__cd) $(srcdir) && \ + $$restore $$backupdir/* `echo "./$@" | sed 's|[^/]*$$||'`; \ + fi; \ + rm -rf $$backupdir; exit $$rc + +.texi.dvi: + $(AM_V_TEXI2DVI)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ + MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ + $(TEXI2DVI) $(AM_V_texinfo) --build-dir=$(@:.dvi=.t2d) -o $@ $(AM_V_texidevnull) \ + $< + +.texi.pdf: + $(AM_V_TEXI2PDF)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ + MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ + $(TEXI2PDF) $(AM_V_texinfo) --build-dir=$(@:.pdf=.t2p) -o $@ $(AM_V_texidevnull) \ + $< + +.texi.html: + $(AM_V_MAKEINFO)rm -rf $(@:.html=.htp) + $(AM_V_at)if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ + -o $(@:.html=.htp) $<; \ + then \ + rm -rf $@ && mv $(@:.html=.htp) $@; \ + else \ + rm -rf $(@:.html=.htp); exit 1; \ + fi +$(srcdir)/mu4e.info: mu4e.texi $(srcdir)/version.texi $(mu4e_TEXINFOS) +mu4e.dvi: mu4e.texi $(srcdir)/version.texi $(mu4e_TEXINFOS) +mu4e.pdf: mu4e.texi $(srcdir)/version.texi $(mu4e_TEXINFOS) +mu4e.html: mu4e.texi $(srcdir)/version.texi $(mu4e_TEXINFOS) +$(srcdir)/version.texi: $(srcdir)/stamp-vti +$(srcdir)/stamp-vti: mu4e.texi $(top_srcdir)/configure + @(dir=.; test -f ./mu4e.texi || dir=$(srcdir); \ + set `$(SHELL) $(top_srcdir)/build-aux/mdate-sh $$dir/mu4e.texi`; \ + echo "@set UPDATED $$1 $$2 $$3"; \ + echo "@set UPDATED-MONTH $$2 $$3"; \ + echo "@set EDITION $(VERSION)"; \ + echo "@set VERSION $(VERSION)") > vti.tmp$$$$ && \ + (cmp -s vti.tmp$$$$ $(srcdir)/version.texi \ + || (echo "Updating $(srcdir)/version.texi" && \ + cp vti.tmp$$$$ $(srcdir)/version.texi.tmp$$$$ && \ + mv $(srcdir)/version.texi.tmp$$$$ $(srcdir)/version.texi)) && \ + rm -f vti.tmp$$$$ $(srcdir)/version.texi.$$$$ + @cp $(srcdir)/version.texi $@ + +mostlyclean-vti: + -rm -f vti.tmp* $(srcdir)/version.texi.tmp* + +maintainer-clean-vti: + -rm -f $(srcdir)/stamp-vti $(srcdir)/version.texi +.dvi.ps: + $(AM_V_DVIPS)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ + $(DVIPS) $(AM_V_texinfo) -o $@ $< + +uninstall-dvi-am: + @$(NORMAL_UNINSTALL) + @list='$(DVIS)'; test -n "$(dvidir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(dvidir)/$$f'"; \ + rm -f "$(DESTDIR)$(dvidir)/$$f"; \ + done + +uninstall-html-am: + @$(NORMAL_UNINSTALL) + @list='$(HTMLS)'; test -n "$(htmldir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " rm -rf '$(DESTDIR)$(htmldir)/$$f'"; \ + rm -rf "$(DESTDIR)$(htmldir)/$$f"; \ + done + +uninstall-info-am: + @$(PRE_UNINSTALL) + @if test -d '$(DESTDIR)$(infodir)' && $(am__can_run_installinfo); then \ + list='$(INFO_DEPS)'; \ + for file in $$list; do \ + relfile=`echo "$$file" | sed 's|^.*/||'`; \ + echo " install-info --info-dir='$(DESTDIR)$(infodir)' --remove '$(DESTDIR)$(infodir)/$$relfile'"; \ + if install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$$relfile"; \ + then :; else test ! -f "$(DESTDIR)$(infodir)/$$relfile" || exit 1; fi; \ + done; \ + else :; fi + @$(NORMAL_UNINSTALL) + @list='$(INFO_DEPS)'; \ + for file in $$list; do \ + relfile=`echo "$$file" | sed 's|^.*/||'`; \ + relfile_i=`echo "$$relfile" | sed 's|\.info$$||;s|$$|.i|'`; \ + (if test -d "$(DESTDIR)$(infodir)" && cd "$(DESTDIR)$(infodir)"; then \ + echo " cd '$(DESTDIR)$(infodir)' && rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]"; \ + rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]; \ + else :; fi); \ + done + +uninstall-pdf-am: + @$(NORMAL_UNINSTALL) + @list='$(PDFS)'; test -n "$(pdfdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(pdfdir)/$$f'"; \ + rm -f "$(DESTDIR)$(pdfdir)/$$f"; \ + done + +uninstall-ps-am: + @$(NORMAL_UNINSTALL) + @list='$(PSS)'; test -n "$(psdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(psdir)/$$f'"; \ + rm -f "$(DESTDIR)$(psdir)/$$f"; \ + done + +dist-info: $(INFO_DEPS) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + list='$(INFO_DEPS)'; \ + for base in $$list; do \ + case $$base in \ + $(srcdir)/*) base=`echo "$$base" | sed "s|^$$srcdirstrip/||"`;; \ + esac; \ + if test -f $$base; then d=.; else d=$(srcdir); fi; \ + base_i=`echo "$$base" | sed 's|\.info$$||;s|$$|.i|'`; \ + for file in $$d/$$base $$d/$$base-[0-9] $$d/$$base-[0-9][0-9] $$d/$$base_i[0-9] $$d/$$base_i[0-9][0-9]; do \ + if test -f $$file; then \ + relfile=`expr "$$file" : "$$d/\(.*\)"`; \ + test -f "$(distdir)/$$relfile" || \ + cp -p $$file "$(distdir)/$$relfile"; \ + else :; fi; \ + done; \ + done + +mostlyclean-aminfo: + -rm -rf mu4e.t2d mu4e.t2p + +clean-aminfo: + -test -z "mu4e.dvi mu4e.pdf mu4e.ps mu4e.html" \ + || rm -rf mu4e.dvi mu4e.pdf mu4e.ps mu4e.html + +maintainer-clean-aminfo: + @list='$(INFO_DEPS)'; for i in $$list; do \ + i_i=`echo "$$i" | sed 's|\.info$$||;s|$$|.i|'`; \ + echo " rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]"; \ + rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]; \ + done + +.el.elc: + if test '$(EMACS)' != no; then \ + am__dir=. am__subdir_includes=''; \ + case $@ in */*) \ + am__dir=`echo '$@' | sed 's,/[^/]*$$,,'`; \ + am__subdir_includes="-L $$am__dir -L $(srcdir)/$$am__dir"; \ + esac; \ + test -d "$$am__dir" || $(MKDIR_P) "$$am__dir" || exit 1; \ + $(EMACS) --batch \ + $(AM_ELCFLAGS) $(ELCFLAGS) \ + $$am__subdir_includes -L $(builddir) -L $(srcdir) \ + --eval '$(am__emacs_byte_compile_setup)' \ + -f batch-byte-compile '$<'; \ + else :; fi + +install-dist_lispLISP: $(dist_lisp_LISP) $(ELCFILES) + @$(NORMAL_INSTALL) + @if test "$(EMACS)" != no && test -n "$(lispdir)"; then \ + list='$(dist_lisp_LISP)'; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(lispdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(lispdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + $(am__strip_dir) \ + echo " $(dist_lispLISP_INSTALL) '$$d$$p' '$(DESTDIR)$(lispdir)/$$f'"; \ + $(dist_lispLISP_INSTALL) "$$d$$p" "$(DESTDIR)$(lispdir)/$$f" || exit $$?; \ + if test -f $${p}c; then \ + echo " $(dist_lispLISP_INSTALL) '$${p}c' '$(DESTDIR)$(lispdir)/$${f}c'"; \ + $(dist_lispLISP_INSTALL) "$${p}c" "$(DESTDIR)$(lispdir)/$${f}c" || exit $$?; \ + else : ; fi; \ + done; \ + else : ; fi + +uninstall-dist_lispLISP: + @$(NORMAL_UNINSTALL) + @test "$(EMACS)" != no && test -n "$(lispdir)" || exit 0; \ + list='$(dist_lisp_LISP)'; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + files="$$files "`echo "$$files" | sed 's|$$|c|'`; \ + dir='$(DESTDIR)$(lispdir)'; $(am__uninstall_files_from_dir) + +clean-lisp: + -rm -f $(ELCFILES) +install-docDATA: $(doc_DATA) + @$(NORMAL_INSTALL) + @list='$(doc_DATA)'; test -n "$(docdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \ + done + +uninstall-docDATA: + @$(NORMAL_UNINSTALL) + @list='$(doc_DATA)'; test -n "$(docdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" +check-valgrind-local: +check-valgrind-memcheck-local: +check-valgrind-helgrind-local: +check-valgrind-drd-local: +check-valgrind-sgcheck-local: + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" distdir="$(distdir)" \ + dist-info +check-am: all-am +check: check-recursive +all-am: Makefile $(INFO_DEPS) $(LISP) $(ELCFILES) $(DATA) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(infodir)" "$(DESTDIR)$(lispdir)" "$(DESTDIR)$(docdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +check-valgrind: check-valgrind-recursive + +check-valgrind-am: check-valgrind-local + +check-valgrind-drd: check-valgrind-drd-recursive + +check-valgrind-drd-am: check-valgrind-drd-local + +check-valgrind-helgrind: check-valgrind-helgrind-recursive + +check-valgrind-helgrind-am: check-valgrind-helgrind-local + +check-valgrind-memcheck: check-valgrind-memcheck-recursive + +check-valgrind-memcheck-am: check-valgrind-memcheck-local + +check-valgrind-sgcheck: check-valgrind-sgcheck-recursive + +check-valgrind-sgcheck-am: check-valgrind-sgcheck-local + +clean: clean-recursive + +clean-am: clean-aminfo clean-generic clean-libtool clean-lisp \ + mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: $(DVIS) + +html: html-recursive + +html-am: $(HTMLS) + +info: info-recursive + +info-am: $(INFO_DEPS) + +install-data-am: install-dist_lispLISP install-docDATA install-info-am + +install-dvi: install-dvi-recursive + +install-dvi-am: $(DVIS) + @$(NORMAL_INSTALL) + @list='$(DVIS)'; test -n "$(dvidir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(dvidir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(dvidir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dvidir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(dvidir)" || exit $$?; \ + done +install-exec-am: + +install-html: install-html-recursive + +install-html-am: $(HTMLS) + @$(NORMAL_INSTALL) + @list='$(HTMLS)'; list2=; test -n "$(htmldir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(htmldir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p" || test -d "$$p"; then d=; else d="$(srcdir)/"; fi; \ + $(am__strip_dir) \ + d2=$$d$$p; \ + if test -d "$$d2"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)/$$f'"; \ + $(MKDIR_P) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \ + echo " $(INSTALL_DATA) '$$d2'/* '$(DESTDIR)$(htmldir)/$$f'"; \ + $(INSTALL_DATA) "$$d2"/* "$(DESTDIR)$(htmldir)/$$f" || exit $$?; \ + else \ + list2="$$list2 $$d2"; \ + fi; \ + done; \ + test -z "$$list2" || { echo "$$list2" | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(htmldir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(htmldir)" || exit $$?; \ + done; } +install-info: install-info-recursive + +install-info-am: $(INFO_DEPS) + @$(NORMAL_INSTALL) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(infodir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(infodir)" || exit 1; \ + fi; \ + for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + esac; \ + if test -f $$file; then d=.; else d=$(srcdir); fi; \ + file_i=`echo "$$file" | sed 's|\.info$$||;s|$$|.i|'`; \ + for ifile in $$d/$$file $$d/$$file-[0-9] $$d/$$file-[0-9][0-9] \ + $$d/$$file_i[0-9] $$d/$$file_i[0-9][0-9] ; do \ + if test -f $$ifile; then \ + echo "$$ifile"; \ + else : ; fi; \ + done; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(infodir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(infodir)" || exit $$?; done + @$(POST_INSTALL) + @if $(am__can_run_installinfo); then \ + list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \ + for file in $$list; do \ + relfile=`echo "$$file" | sed 's|^.*/||'`; \ + echo " install-info --info-dir='$(DESTDIR)$(infodir)' '$(DESTDIR)$(infodir)/$$relfile'";\ + install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$$relfile" || :;\ + done; \ + else : ; fi +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: $(PDFS) + @$(NORMAL_INSTALL) + @list='$(PDFS)'; test -n "$(pdfdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pdfdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pdfdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pdfdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pdfdir)" || exit $$?; done +install-ps: install-ps-recursive + +install-ps-am: $(PSS) + @$(NORMAL_INSTALL) + @list='$(PSS)'; test -n "$(psdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(psdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(psdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(psdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(psdir)" || exit $$?; done +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-aminfo \ + maintainer-clean-generic maintainer-clean-vti + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-aminfo mostlyclean-generic \ + mostlyclean-libtool mostlyclean-vti + +pdf: pdf-recursive + +pdf-am: $(PDFS) + +ps: ps-recursive + +ps-am: $(PSS) + +uninstall-am: uninstall-dist_lispLISP uninstall-docDATA \ + uninstall-dvi-am uninstall-html-am uninstall-info-am \ + uninstall-pdf-am uninstall-ps-am + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am check-valgrind-am check-valgrind-drd-am \ + check-valgrind-drd-local check-valgrind-helgrind-am \ + check-valgrind-helgrind-local check-valgrind-local \ + check-valgrind-memcheck-am check-valgrind-memcheck-local \ + check-valgrind-sgcheck-am check-valgrind-sgcheck-local clean \ + clean-aminfo clean-generic clean-libtool clean-lisp \ + cscopelist-am ctags ctags-am dist-info distclean \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dist_lispLISP \ + install-docDATA install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-aminfo maintainer-clean-generic \ + maintainer-clean-vti mostlyclean mostlyclean-aminfo \ + mostlyclean-generic mostlyclean-libtool mostlyclean-vti pdf \ + pdf-am ps ps-am tags tags-am uninstall uninstall-am \ + uninstall-dist_lispLISP uninstall-docDATA uninstall-dvi-am \ + uninstall-html-am uninstall-info-am uninstall-pdf-am \ + uninstall-ps-am + +.PRECIOUS: Makefile + + +# NOTE: we set the locale/tz to some well-know values, so the tests +# (at least when running under 'make check') run in a predictable +# environment. There are specific tests different timezone, though. +# +test: all $(TEST_PROGS) + @export LC_ALL="en_US.utf8" + @export TZ="Europe/Helsinki" + @test -z "$(TEST_PROGS)" || gtester --verbose $(TEST_PROGS) || exit $$?; \ + test -z "$(SUBDIRS)" || \ + for subdir in $(SUBDIRS); do \ + test "$$subdir" = "." || \ + (cd ./$$subdir && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $$? ; \ + done + +.PHONY: test gprof +fancyhtml: + mkdir -p $(BUILDPATH) ; cp -R $(TEXINFO_CSS_PATH)/static $(BUILDPATH) + makeinfo --html --css-ref=static/css/texinfo-klare.css -o $(BUILDPATH) mu4e.texi + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/elisp/mu4e/TODO b/elisp/mu4e/TODO new file mode 100644 index 0000000..327fc1b --- /dev/null +++ b/elisp/mu4e/TODO @@ -0,0 +1,19 @@ +* TODO + +*** mu4e-get-sub-maildirs +*** extract mailing list name +*** mark thread +*** bounce support +*** sorting +*** tool bars +*** refiling-by-pattern +*** inspect message (muile) +*** message statistics +*** include exchange handling / org integration +*** integrate bbdb +*** identity support + + +# Local Variables: +# mode: org; org-startup-folded: nil +# End: diff --git a/elisp/mu4e/fdl.texi b/elisp/mu4e/fdl.texi new file mode 100644 index 0000000..96ce74e --- /dev/null +++ b/elisp/mu4e/fdl.texi @@ -0,0 +1,451 @@ +@c The GNU Free Documentation License. +@center Version 1.2, November 2002 + +@c This file is intended to be included within another document, +@c hence no sectioning command or @node. + +@display +Copyright @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. +@end display + +@enumerate 0 +@item +PREAMBLE + +The purpose of this License is to make a manual, textbook, or other +functional and useful document @dfn{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. + +@item +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 +@sc{ascii} without markup, Texinfo input format, La@TeX{} input +format, @acronym{SGML} or @acronym{XML} using a publicly available +@acronym{DTD}, and standard-conforming simple @acronym{HTML}, +PostScript or @acronym{PDF} designed for human modification. Examples +of transparent image formats include @acronym{PNG}, @acronym{XCF} and +@acronym{JPG}. Opaque formats include proprietary formats that can be +read and edited only by proprietary word processors, @acronym{SGML} or +@acronym{XML} for which the @acronym{DTD} and/or processing tools are +not generally available, and the machine-generated @acronym{HTML}, +PostScript or @acronym{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. + +@item +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. + +@item +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. + +@item +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: + +@enumerate A +@item +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. + +@item +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. + +@item +State on the Title page the name of the publisher of the +Modified Version, as the publisher. + +@item +Preserve all the copyright notices of the Document. + +@item +Add an appropriate copyright notice for your modifications +adjacent to the other copyright notices. + +@item +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. + +@item +Preserve in that license notice the full lists of Invariant Sections +and required Cover Texts given in the Document's license notice. + +@item +Include an unaltered copy of this License. + +@item +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. + +@item +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. + +@item +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. + +@item +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. + +@item +Delete any section Entitled ``Endorsements''. Such a section +may not be included in the Modified Version. + +@item +Do not retitle any existing section to be Entitled ``Endorsements'' or +to conflict in title with any Invariant Section. + +@item +Preserve any Warranty Disclaimers. +@end enumerate + +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. + +@item +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.'' + +@item +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. + +@item +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. + +@item +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. + +@item +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. + +@item +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 +@uref{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. +@end enumerate + +@page +@heading 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: + +@smallexample +@group + Copyright (C) @var{year} @var{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''. +@end group +@end smallexample + +If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, +replace the ``with@dots{}Texts.'' line with this: + +@smallexample +@group + with the Invariant Sections being @var{list their titles}, with + the Front-Cover Texts being @var{list}, and with the Back-Cover Texts + being @var{list}. +@end group +@end smallexample + +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. + +@c Local Variables: +@c ispell-local-pdict: "ispell-dict" +@c End: + diff --git a/elisp/mu4e/mu4e-about.org b/elisp/mu4e/mu4e-about.org new file mode 100644 index 0000000..5c015b3 --- /dev/null +++ b/elisp/mu4e/mu4e-about.org @@ -0,0 +1,15 @@ +#+STARTUP:showall +* About mu4e + + *mu4e* is an emacs e-mail client based on the [[http://djcbsoftware.nl/code/mu][mu]] email search engine. It was + written & designed by /Dirk-Jan C. Binnema/, with contributions from others. + + *mu4e* and *mu* are free software, licensed under the terms of the [[http://www.gnu.org/licenses/gpl-3.0.html][GNU GPLv3]]. + + You can get the code from [[https://github.com/djcb/mu][the git repository]]; there, you can also + [[https://github.com/djcb/mu/issues][file bugs and feature requests]]. + + *mu4e* has its own [[info:mu4e][manual]], which includes an [[info:mu4e#FAQ%20-%20Frequently%20Anticipated%20Questions][FAQ]]. If that is not enough, + there's also the [[http://groups.google.com/group/mu-discuss][mu mailing list]]. + + [Press *q* to quit this buffer] diff --git a/elisp/mu4e/mu4e-actions.el b/elisp/mu4e/mu4e-actions.el new file mode 100644 index 0000000..2c8af24 --- /dev/null +++ b/elisp/mu4e/mu4e-actions.el @@ -0,0 +1,253 @@ +;;; mu4e-actions.el -- part of mu4e, the mu mail user agent -*- lexical-binding: t -*- + +;; Copyright (C) 2011-2021 Dirk-Jan C. Binnema + +;; Author: Dirk-Jan C. Binnema +;; Maintainer: Dirk-Jan C. Binnema + +;; This file is not part of GNU Emacs. + +;; mu4e is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; mu4e is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with mu4e. If not, see . + +;;; Commentary: + +;; Example actions for messages, attachments (see chapter 'Actions' in the +;; manual) + +;;; Code: + +(require 'cl-lib) +(require 'ido) + +(require 'mu4e-utils) +(require 'mu4e-message) +(require 'mu4e-meta) + +(declare-function mu4e~proc-extract "mu4e-proc") +(declare-function mu4e-headers-search "mu4e-headers") + +(defvar mu4e-headers-include-related) +(defvar mu4e-headers-show-threads) +(defvar mu4e-view-show-addresses) +(defvar mu4e-view-date-format) + + +;;; Count lines + +(defun mu4e-action-count-lines (msg) + "Count the number of lines in the e-mail MSG. +Works for headers view and message-view." + (message "Number of lines: %s" + (shell-command-to-string + (concat "wc -l < " (shell-quote-argument (mu4e-message-field msg :path)))))) + +;;; Org Helpers + +(defvar mu4e-captured-message nil + "The most recently captured message.") + +(defun mu4e-action-capture-message (msg) + "Remember MSG. +Later, we can create an attachment based on this message with +`mu4e-compose-attach-captured-message'." + (setq mu4e-captured-message msg) + (message "Message has been captured")) + + +(defun mu4e-action-copy-message-file-path (msg) + "Save the full path for the current MSG to the kill ring." + (kill-new (mu4e-message-field msg :path))) + +(defvar mu4e-org-contacts-file nil + "File to store contact information for org-contacts. +Needed by `mu4e-action-add-org-contact'.") + +(eval-when-compile ;; silence compiler warning about free variable + (unless (require 'org-capture nil 'noerror) + (defvar org-capture-templates nil))) + +(defun mu4e-action-add-org-contact (msg) + "Add an org-contact based on the sender ddress of the current MSG. +You need to set `mu4e-org-contacts-file' to the full path to the +file where you store your org-contacts." + (unless (require 'org-capture nil 'noerror) + (mu4e-error "Feature org-capture is not available")) + (unless mu4e-org-contacts-file + (mu4e-error "Variable `mu4e-org-contacts-file' is nil")) + (let* ((sender (car-safe (mu4e-message-field msg :from))) + (name (car-safe sender)) (email (cdr-safe sender)) + (blurb + (format + (concat + "* %%?%s\n" + ":PROPERTIES:\n" + ":EMAIL: %s\n" + ":NICK:\n" + ":BIRTHDAY:\n" + ":END:\n\n") + (or name email "") + (or email ""))) + (key "mu4e-add-org-contact-key") + (org-capture-templates + (append org-capture-templates + (list (list key "contacts" 'entry + (list 'file mu4e-org-contacts-file) blurb))))) + (message "%S" org-capture-templates) + (when (fboundp 'org-capture) + (org-capture nil key)))) + +;;; Patches + +(defvar mu4e~patch-directory-history nil + "History of directories we have applied patches to.") + +;; This essentially works around the fact that read-directory-name +;; can't have custom history. +(defun mu4e~read-patch-directory (&optional prompt) + "Read a `PROMPT'ed directory name via `completing-read' with history." + (unless prompt + (setq prompt "Target directory:")) + (file-truename + (completing-read prompt 'read-file-name-internal #'file-directory-p + nil nil 'mu4e~patch-directory-history))) + +(defun mu4e-action-git-apply-patch (msg) + "Apply `MSG' as a git patch." + (let ((path (mu4e~read-patch-directory "Target directory: "))) + (let ((default-directory path)) + (shell-command + (format "git apply %s" + (shell-quote-argument (mu4e-message-field msg :path))))))) + +(defun mu4e-action-git-apply-mbox (msg &optional signoff) + "Apply `MSG' a git patch with optional `SIGNOFF'. + +If the `default-directory' matches the most recent history entry don't +bother asking for the git tree again (useful for bulk actions)." + + (let ((cwd (substring-no-properties + (or (car mu4e~patch-directory-history) + "not-a-dir")))) + (unless (and (stringp cwd) (string= default-directory cwd)) + (setq cwd (mu4e~read-patch-directory "Target directory: "))) + (let ((default-directory cwd)) + (shell-command + (format "git am %s %s" + (if signoff "--signoff" "") + (shell-quote-argument (mu4e-message-field msg :path))))))) + +;;; Tagging + +(defvar mu4e-action-tags-header "X-Keywords" + "Header where tags are stored. +Used by `mu4e-action-retag-message'. 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.") + +(defvar mu4e-action-tags-completion-list '() + "List of tags for completion in `mu4e-action-retag-message'.") + +(defun mu4e~contains-line-matching (regexp path) + "Return non-nil if the file at PATH contain a line matching REGEXP. +Otherwise return nil." + (with-temp-buffer + (insert-file-contents path) + (save-excursion + (goto-char (point-min)) + (re-search-forward regexp nil t)))) + +(defun mu4e~replace-first-line-matching (regexp to-string path) + "Replace first line matching REGEXP in PATH with TO-STRING." + (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 MSG with RETAG-ARG. + +RETAG-ARG is a comma-separated list of additions and removals. + +Example: +tag,+long tag,-oldtag +would add 'tag' and 'long tag', and remove 'oldtag'." + (let* ( + (path (mu4e-message-field msg :path)) + (oldtags (mu4e-message-field msg :tags)) + (tags-completion + (append + mu4e-action-tags-completion-list + (mapcar (lambda (tag) (format "+%s" tag)) + mu4e-action-tags-completion-list) + (mapcar (lambda (tag) (format "-%s" tag)) + oldtags))) + (retag (if retag-arg + (split-string retag-arg ",") + (completing-read-multiple "Tags: " tags-completion))) + (header mu4e-action-tags-header) + (sep (cond ((string= header "Keywords") ", ") + ((string= header "X-Label") " ") + ((string= header "X-Keywords") ", ") + (t ", "))) + (taglist (if oldtags (copy-sequence oldtags) '())) + tagstr) + (dolist (tag retag taglist) + (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)) + (setq tagstr (replace-regexp-in-string "[/]" "\\&" tagstr)) + + (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))) + +(defun mu4e-action-show-thread (msg) + "Show thread for message at point with point remaining on MSG. +I.e., point remains on the message with the message-id where the +action was invoked. If invoked in view mode, continue to display +the message." + (let ((msgid (mu4e-message-field msg :message-id))) + (when msgid + (let ((mu4e-headers-show-threads t) + (mu4e-headers-include-related t)) + (mu4e-headers-search + (format "msgid:%s" msgid) + nil nil nil + msgid (and (eq major-mode 'mu4e-view-mode) + (not (eq mu4e-split-view 'single-window)))))))) + +;;; _ +(provide 'mu4e-actions) +;;; mu4e-actions.el ends here diff --git a/elisp/mu4e/mu4e-compose.el b/elisp/mu4e/mu4e-compose.el new file mode 100644 index 0000000..2ae566e --- /dev/null +++ b/elisp/mu4e/mu4e-compose.el @@ -0,0 +1,1114 @@ +;;; mu4e-compose.el -- part of mu4e, the mu mail user agent for emacs -*- lexical-binding: t -*- + +;; Copyright (C) 2011-2020 Dirk-Jan C. Binnema + +;; Author: Dirk-Jan C. Binnema +;; Maintainer: Dirk-Jan C. Binnema + +;; This file is not part of GNU Emacs. + +;; mu4e is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; mu4e is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with mu4e. If not, see . + +;;; Commentary: + +;; In this file, various functions to compose/send messages, piggybacking on +;; gnus' message mode + +;; Magic / Rupe Goldberg + +;; 1) When we reply/forward a message, we get it from the backend, ie: +;; we send to the backend (mu4e-compose): +;; compose type:reply docid:30935 +;; backend responds with: +;; (:compose reply :original ( .... )) + +;; 2) When we compose a message, message and headers are separated by +;; `mail-header-separator', ie. '--text follows this line--. We use +;; before-save-hook and after-save-hook to remove/re-add this special line, so +;; it stays in the buffer, but never hits the disk. +;; see: +;; mu4e~compose-insert-mail-header-separator +;; mu4e~compose-remove-mail-header-separator +;; +;; (maybe we can get away with remove it only just before sending? what does +;; gnus do?) + +;; 3) When sending a message, we want to do a few things: +;; a) move the message from drafts to the sent folder (maybe; depends on +;; `mu4e-sent-messages-behavior') +;; b) if it's a reply, mark the replied-to message as "R", i.e. replied +;; if it's a forward, mark the forwarded message as "P", i.e. +;; passed (forwarded) +;; c) kill all buffers looking at the sent message + +;; a) is dealt with by message-mode, but we need to tell it where to move the +;; sent message. We do this by adding an Fcc: header with the target folder, +;; see `mu4e~compose-setup-fcc-maybe'. Since message-mode does not natively +;; understand maildirs, we also need to tell it what to do, so we also set +;; `message-fcc-handler-function' there. Finally, we add the the message in +;; the sent-folder to the database. +;; +;; b) this is handled in `mu4e~compose-set-parent-flag' +;; +;; c) this is handled in our handler for the `sent'-message from the backend +;; (`mu4e-sent-handler') + +;;; Code: + +(require 'cl-lib) +(require 'message) +(require 'mail-parse) +(require 'smtpmail) +(require 'rfc2368) + +(require 'mu4e-utils) +(require 'mu4e-vars) +(require 'mu4e-proc) +(require 'mu4e-actions) +(require 'mu4e-message) +(require 'mu4e-draft) +(require 'mu4e-context) + +;;; Composing / Sending messages + +(defgroup mu4e-compose nil + "Customizations for composing/sending messages." + :group 'mu4e) + +(defcustom mu4e-sent-messages-behavior 'sent + "Determines what mu4e does with sent messages. + +This is one of the symbols: +* `sent' move the sent message to the Sent-folder (`mu4e-sent-folder') +* `trash' move the sent message to the Trash-folder (`mu4e-trash-folder') +* `delete' delete the sent message. + +Note, when using GMail/IMAP, you should set this to either +`trash' or `delete', since GMail already takes care of keeping +copies in the sent folder. + +Alternatively, `mu4e-sent-messages-behavior' can be a function +which takes no arguments, and which should return one of the mentioned +symbols, for example: + + (setq mu4e-sent-messages-behavior (lambda () + (if (string= (message-sendmail-envelope-from) \"foo@example.com\") + 'delete 'sent))) + +The various `message-' functions from `message-mode' are available +for querying the message information." + :type '(choice (const :tag "move message to mu4e-sent-folder" sent) + (const :tag "move message to mu4e-trash-folder" trash) + (const :tag "delete message" delete)) + :group 'mu4e-compose) + +(defcustom mu4e-compose-context-policy 'ask + "Policy for determining the context when composing a new message. + +If the value is `always-ask', ask the user unconditionally. + +In all other cases, if any context matches (using its match +function), this context is used. Otherwise, if none of the +contexts match, we have the following choices: + +- `pick-first': pick the first of the contexts available (ie. the default) +- `ask': ask the user +- `ask-if-none': ask if there is no context yet, otherwise leave it as it is +- nil: return nil; leaves the current context as is. + +Also see `mu4e-context-policy'." + :type '(choice + (const :tag "Always ask what context to use" always-ask) + (const :tag "Ask if none of the contexts match" ask) + (const :tag "Ask when there's no context yet" ask-if-none) + (const :tag "Pick the first context if none match" pick-first) + (const :tag "Don't change the context when none match" nil)) + :safe 'symbolp + :group 'mu4e-compose) + +(defcustom mu4e-compose-crypto-policy + '(encrypt-encrypted-replies sign-encrypted-replies) + "Policy to control when messages will be signed/encrypted. + +The value is a list, whose members determine the behaviour of +`mu4e~compose-crypto-message'. Specifically, it might contain: + +- `sign-all-messages': Always add a signature. +- `sign-new-messages': Add a signature to new message, ie. + messages that aren't responses to another message. +- `sign-forwarded-messages': Add a signature when forwarding + a message +- `sign-edited-messages': Add a signature to drafts +- `sign-all-replies': Add a signature when responding to + another message. +- `sign-plain-replies': Add a signature when responding to + non-encrypted messages. +- `sign-encrypted-replies': Add a signature when responding + to encrypted messages. + +It should be noted that certain symbols have priorities over one +another. So `sign-all-messages' implies `sign-all-replies', which +in turn implies `sign-plain-replies'. Adding both to the set, is +not a contradiction, but a redundant configuration. + +All `sign-*' options have a `encrypt-*' analogue." + :type '(set :greedy t + (const :tag "Sign all messages" sign-all-messages) + (const :tag "Encrypt all messages" encrypt-all-messages) + (const :tag "Sign new messages" sign-new-messages) + (const :tag "Encrypt new messages" encrypt-new-messages) + (const :tag "Sign forwarded messages" sign-forwarded-messages) + (const :tag "Encrypt forwarded messages" encrypt-forwarded-messages) + (const :tag "Sign edited messages" sign-edited-messages) + (const :tag "Encrypt edited messages" edited-forwarded-messages) + (const :tag "Sign all replies" sign-all-replies) + (const :tag "Encrypt all replies" encrypt-all-replies) + (const :tag "Sign replies to plain messages" sign-plain-replies) + (const :tag "Encrypt replies to plain messages" encrypt-plain-replies) + (const :tag "Sign replies to encrypted messages" sign-encrypted-replies) + (const :tag "Encrypt replies to encrypted messages" encrypt-encrypted-replies)) + :group 'mu4e-compose) + +(defcustom mu4e-compose-crypto-reply-encrypted-policy nil + "Policy for signing/encrypting replies to encrypted messages. +We have the following choices: + +- `sign': sign the reply +- `sign-and-encrypt': sign and encrypt the reply +- `encrypt': encrypt the reply, but don't sign it. +- anything else: do nothing." + :type '(choice + (const :tag "Sign the reply" sign) + (const :tag "Sign and encrypt the reply" sign-and-encrypt) + (const :tag "Encrypt the reply" encrypt) + (const :tag "Don't do anything" nil)) + :safe 'symbolp + :group 'mu4e-compose) + +(make-obsolete-variable 'mu4e-compose-crypto-reply-encrypted-policy "The use of the + 'mu4e-compose-crypto-reply-encrypted-policy' variable is deprecated. + 'mu4e-compose-crypto-policy' should be used instead" + "2020-03-06") + +(defcustom mu4e-compose-crypto-reply-plain-policy nil + "Policy for signing/encrypting replies to messages received unencrypted. +We have the following choices: + +- `sign': sign the reply +- `sign-and-encrypt': sign and encrypt the reply +- `encrypt': encrypt the reply, but don't sign it. +- anything else: do nothing." + :type '(choice + (const :tag "Sign the reply" sign) + (const :tag "Sign and encrypt the reply" sign-and-encrypt) + (const :tag "Encrypt the reply" encrypt) + (const :tag "Don't do anything" nil)) + :safe 'symbolp + :group 'mu4e-compose) + +(make-obsolete-variable 'mu4e-compose-crypto-reply-plain-policy "The use of the + 'mu4e-compose-crypto-reply-plain-policy' variable is deprecated. + 'mu4e-compose-crypto-policy' should be used instead" + "2020-03-06") + +(make-obsolete-variable 'mu4e-compose-crypto-reply-policy "The use of the + 'mu4e-compose-crypto-reply-policy' variable is deprecated. + 'mu4e-compose-crypto-reply-plain-policy' and + 'mu4e-compose-crypto-reply-encrypted-policy' should be used instead" + "2017-09-02") + +(defcustom mu4e-compose-format-flowed nil + "Whether to compose messages to be sent as format=flowed. +\(Or with long lines if variable `use-hard-newlines' is set to +nil). The variable `fill-flowed-encode-column' lets you customize +the width beyond which format=flowed lines are wrapped." + :type 'boolean + :safe 'booleanp + :group 'mu4e-compose) + +(defcustom mu4e-compose-pre-hook nil + "Hook run just *before* message composition starts. +If the compose-type is either 'reply' or 'forward', the variable +`mu4e-compose-parent-message' points to the message replied to / +being forwarded / edited, and `mu4e-compose-type' contains the +type of message to be composed. + +Note that there is no draft message yet when this hook runs, it +is meant for influencing the how mu4e constructs the draft +message. If you want to do something with the draft messages after +it has been constructed, `mu4e-compose-mode-hook' would be the +place to do that." + :type 'hook + :group 'mu4e-compose) + +(defvar mu4e-compose-type nil + "The compose-type for this buffer. +This is a symbol, `new', `forward', `reply' or `edit'.") + +;;; Attachments + +(defun mu4e-compose-attach-message (msg) + "Insert message MSG as an attachment." + (let ((path (plist-get msg :path))) + (unless (file-exists-p path) + (mu4e-warn "Message file not found")) + (mml-attach-file + path + "message/rfc822" + (or (plist-get msg :subject) "No subject") + "attachment"))) + +(defun mu4e-compose-attach-captured-message () + "Insert the last captured message file as an attachment. +Messages are captured with `mu4e-action-capture-message'." + (interactive) + (unless mu4e-captured-message + (mu4e-warn "No message has been captured")) + (mu4e-compose-attach-message mu4e-captured-message)) + +;;; Misc + +;; 'fcc' refers to saving a copy of a sent message to a certain folder. that's +;; what these 'Sent mail' folders are for! +;; +;; We let message mode take care of this by adding a field + +;; Fcc: + +;; in the "message-send-hook" (ie., just before sending). message mode will +;; then take care of the saving when the message is actually sent. +;; +;; note, where and if you make this copy depends on the value of +;; `mu4e-sent-messages-behavior'. + +(defun mu4e~compose-setup-fcc-maybe () + "Maybe setup Fcc, based on `mu4e-sent-messages-behavior'. +If needed, set the Fcc header, and register the handler function." + (let* ((sent-behavior + ;; Note; we cannot simply use functionp here, since at least + ;; delete is a function, too... + (if (member mu4e-sent-messages-behavior '(delete trash sent)) + mu4e-sent-messages-behavior + (if (functionp mu4e-sent-messages-behavior) + (funcall mu4e-sent-messages-behavior) + mu4e-sent-messages-behavior))) + (mdir + (cl-case sent-behavior + (delete nil) + (trash (mu4e-get-trash-folder mu4e-compose-parent-message)) + (sent (mu4e-get-sent-folder mu4e-compose-parent-message)) + (otherwise + (mu4e-error "Unsupported value '%S' + `mu4e-sent-messages-behavior'" + mu4e-sent-messages-behavior)))) + (fccfile (and mdir + (concat (mu4e-root-maildir) mdir "/cur/" + (mu4e~draft-message-filename-construct "S"))))) + ;; if there's an fcc header, add it to the file + (when fccfile + (message-add-header (concat "Fcc: " fccfile "\n")) + ;; sadly, we cannot define as 'buffer-local'... this will screw up gnus + ;; etc. if you run it after mu4e so, (hack hack) we reset it to the old + ;; handler after we've done our thing. + (setq message-fcc-handler-function + (let ((maildir mdir) + (old-handler message-fcc-handler-function)) + (lambda (file) + (setq message-fcc-handler-function old-handler) ;; reset the fcc handler + (let ((mdir-path (concat (mu4e-root-maildir) maildir))) + ;; Create the full maildir structure for the sent folder if it doesn't exist. + ;; `mu4e~proc-mkdir` runs asynchronously but no matter whether it runs before or after + ;; `write-file`, the sent maildir ends up in the correct state. + (unless (file-exists-p mdir-path) + (mu4e~proc-mkdir mdir-path))) + (write-file file) ;; writing maildirs files is easy + (mu4e~proc-add file))))))) ;; update the database + +(defvar mu4e-compose-hidden-headers + `("^References:" "^Face:" "^X-Face:" + "^X-Draft-From:" "^User-agent:") + "Hidden headers when composing.") + +(defun mu4e~compose-hide-headers () + "Hide the headers as per `mu4e-compose-hidden-headers'." + (let ((message-hidden-headers mu4e-compose-hidden-headers)) + (message-hide-headers))) + +(defconst mu4e~compose-address-fields-regexp + "^\\(To\\|B?Cc\\|Reply-To\\|From\\):") + +(defun mu4e~compose-register-message-save-hooks () + "Just before saving, we remove the `mail-header-separator'. +Just after saving we restore it; thus, the separator should never +appear on disk. Also update the Date and ensure we have a +Message-ID." + (add-hook 'before-save-hook + #'mu4e~compose-before-save-hook-fn + nil t) + (add-hook 'after-save-hook + #'mu4e~compose-after-save-hook-fn + nil t)) + +(defun mu4e~compose-before-save-hook-fn () + "Add the message-id if necessary and update the date." + (save-excursion + (save-restriction + (message-narrow-to-headers) + (unless (message-fetch-field "Message-ID") + (message-generate-headers '(Date Message-ID)))) + (save-match-data + (mu4e~draft-remove-mail-header-separator)))) + +(defun mu4e~compose-after-save-hook-fn () + (save-match-data + (mu4e~compose-set-friendly-buffer-name) + (mu4e~draft-insert-mail-header-separator) + ;; hide some headers again + (widen) + (mu4e~compose-hide-headers) + (set-buffer-modified-p nil) + (mu4e-message "Saved (%d lines)" (count-lines (point-min) (point-max))) + ;; update the file on disk -- ie., without the separator + (mu4e~proc-add (buffer-file-name)))) + + +;;; address completion + +;; inspired by org-contacts.el and +;; https://github.com/nordlow/elisp/blob/master/mine/completion-styles-cycle.el + +(defun mu4e~compose-complete-handler (str pred action) + "Complete address STR with predication PRED for ACTION." + (cond + ((eq action nil) + (try-completion str mu4e~contacts-hash pred)) + ((eq action t) + (all-completions str mu4e~contacts-hash pred)) + ((eq action 'metadata) + ;; our contacts are already sorted - just need to tell the + ;; completion machinery not to try to undo that... + '(metadata + (display-sort-function . identity) + (cycle-sort-function . identity))))) + +(defun mu4e~compose-complete-contact (&optional start) + "Complete the text at START with a contact. +Ie. either 'name ' or 'email')." + (interactive) + (let ((mail-abbrev-mode-regexp mu4e~compose-address-fields-regexp) + (eoh ;; end-of-headers + (save-excursion + (goto-char (point-min)) + (search-forward-regexp mail-header-separator nil t)))) + ;; try to complete only when we're in the headers area, + ;; looking at an address field. + (when (and eoh (> eoh (point)) (mail-abbrev-in-expansion-header-p)) + (let* ((end (point)) + (start + (or start + (save-excursion + (re-search-backward "\\(\\`\\|[\n:,]\\)[ \t]*") + (goto-char (match-end 0)) + (point))))) + (list start end 'mu4e~compose-complete-handler))))) + +(defun mu4e~compose-setup-completion () + "Set up auto-completion of addresses." + (set (make-local-variable 'completion-ignore-case) t) + (set (make-local-variable 'completion-cycle-threshold) 7) + (add-to-list (make-local-variable 'completion-styles) 'substring) + (add-hook 'completion-at-point-functions + 'mu4e~compose-complete-contact nil t)) + +(defun mu4e~remove-refs-maybe () + "Remove References: if In-Reply-To: is missing. +This allows the user to effectively start a new message-thread by +removing the In-Reply-To header." + (unless (message-fetch-field "in-reply-to") + (message-remove-header "References"))) + +;;; Compose Mode + +(defvar mu4e-compose-mode-map nil + "Keymap for \"*mu4e-compose*\" buffers.") +(unless mu4e-compose-mode-map + (setq mu4e-compose-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "C-S-u") 'mu4e-update-mail-and-index) + (define-key map (kbd "C-c C-;") 'mu4e-compose-context-switch) + (define-key map (kbd "C-c C-u") 'mu4e-update-mail-and-index) + (define-key map (kbd "C-c C-k") 'mu4e-message-kill-buffer) + (define-key map (kbd "M-q") 'mu4e-fill-paragraph) + map))) + +(defun mu4e-fill-paragraph (&optional region) + "Re-layout either the whole message or REGION. +If variable `use-hard-newlines', takes a multi-line paragraph and +makes it into a single line of text. Assume paragraphs are +separated by blank lines. If variable `use-hard-newlines' is not +set, this simply executes `fill-paragraph'." + ;; Inspired by https://www.emacswiki.org/emacs/UnfillParagraph + (interactive (progn (barf-if-buffer-read-only) '(t))) + (ignore-errors + (if mu4e-compose-format-flowed + (let ((fill-column (point-max)) + (use-hard-newlines nil)); rfill "across" hard newlines + (when (use-region-p) + (delete-trailing-whitespace (region-beginning) (region-end))) + (fill-paragraph nil region)) + (when (use-region-p) + (delete-trailing-whitespace (region-beginning) (region-end))) + (fill-paragraph nil region)))) + +(defun mu4e-toggle-use-hard-newlines () + (interactive) + (setq use-hard-newlines (not use-hard-newlines)) + (if use-hard-newlines + (turn-off-auto-fill) + (turn-on-auto-fill))) + +(defun mu4e~compose-remap-faces () + "Remap `message-mode' faces to mu4e ones. +Our parent `message-mode' uses font-locking for the compose +buffers; lets remap its faces so it uses the ones for mu4e." + ;; normal headers + (face-remap-add-relative 'message-header-name + '((:inherit mu4e-header-key-face))) + (face-remap-add-relative 'message-header-other + '((:inherit mu4e-header-value-face))) + ;; special headers + (face-remap-add-relative 'message-header-from + '((:inherit mu4e-contact-face))) + (face-remap-add-relative 'message-header-to + '((:inherit mu4e-contact-face))) + (face-remap-add-relative 'message-header-cc + '((:inherit mu4e-contact-face))) + (face-remap-add-relative 'message-header-bcc + '((:inherit mu4e-contact-face))) + (face-remap-add-relative 'message-header-subject + '((:inherit mu4e-special-header-value-face))) + ;; citation + (face-remap-add-relative 'message-cited-text + '((:inherit mu4e-cited-1-face)))) + +(define-derived-mode mu4e-compose-mode message-mode "mu4e:compose" + "Major mode for the mu4e message composition, derived from `message-mode'. +\\{message-mode-map}." + (progn + (use-local-map mu4e-compose-mode-map) + (mu4e-context-in-modeline) + (set (make-local-variable 'message-signature) mu4e-compose-signature) + ;; set this to allow mu4e to work when gnus-agent is unplugged in gnus + (set (make-local-variable 'message-send-mail-real-function) nil) + (make-local-variable 'message-default-charset) + ;; Set to nil to enable `electric-quote-local-mode' to work: + (make-local-variable 'comment-use-syntax) + (setq comment-use-syntax nil) + ;; message-mode has font-locking, but uses its own faces. Let's + ;; use the mu4e-specific ones instead + (mu4e~compose-remap-faces) + ;; if the default charset is not set, use UTF-8 + (unless message-default-charset + (setq message-default-charset 'utf-8)) + (mu4e~compose-register-message-save-hooks) + ;; offer completion for e-mail addresses + (when mu4e-compose-complete-addresses + (unless mu4e~contacts-hash ;; work-around for https://github.com/djcb/mu/issues/1016 + (mu4e~request-contacts-maybe)) + (mu4e~compose-setup-completion)) + (if mu4e-compose-format-flowed + (progn + (turn-off-auto-fill) + (setq truncate-lines nil + word-wrap t + mml-enable-flowed t + use-hard-newlines t) + (visual-line-mode t)) + (setq mml-enable-flowed nil)) + + ;; set the attachment dir to something more reasonable than the draft + ;; directory. + (setq default-directory (mu4e~get-attachment-dir)) + + (let ((keymap (lookup-key message-mode-map [menu-bar text]))) + (when keymap + (define-key-after + keymap + [mu4e-hard-newlines] + '(menu-item "Format=flowed" mu4e-toggle-use-hard-newlines + :button (:toggle . use-hard-newlines) + :help "Toggle format=flowed" + :visible (eq major-mode 'mu4e-compose-mode) + :enable mu4e-compose-format-flowed) + 'sep) + + (define-key-after + keymap + [mu4e-electric-quote-mode] + '(menu-item "Electric quote" electric-quote-local-mode + :button (:toggle . electric-quote-mode) + :help "Toggle Electric quote mode" + :visible (and (eq major-mode 'mu4e-compose-mode) + (functionp 'electric-quote-local-mode))) + 'mu4e-hard-newlines))) + + (when (lookup-key mml-mode-map [menu-bar Attachments]) + (define-key-after + (lookup-key mml-mode-map [menu-bar Attachments]) + [mu4e-compose-attach-captured-message] + '(menu-item "Attach captured message" + mu4e-compose-attach-captured-message + :help "Attach message captured in Headers View (with 'a c')" + :visible (eq major-mode 'mu4e-compose-mode)) + (quote Attach\ External...))) + + ;; setup the fcc-stuff, if needed + (add-hook 'message-send-hook + #'mu4e~setup-fcc-message-sent-hook-fn + nil t) + ;; when the message has been sent. + (add-hook 'message-sent-hook + #'mu4e~set-sent-handler-message-sent-hook-fn + nil t)) + ;; mark these two hooks as permanent-local, so they'll survive mode-changes + ;; (put 'mu4e~compose-save-before-sending 'permanent-local-hook t) + (put 'mu4e~compose-mark-after-sending 'permanent-local-hook t)) + +(defun mu4e~setup-fcc-message-sent-hook-fn () + ;; mu4e~compose-save-before-sending + ;; when in-reply-to was removed, remove references as well. + (when (eq mu4e-compose-type 'reply) + (mu4e~remove-refs-maybe)) + (when use-hard-newlines + (mu4e-send-harden-newlines)) + ;; for safety, always save the draft before sending + (set-buffer-modified-p t) + (save-buffer) + (mu4e~compose-setup-fcc-maybe) + (widen)) + +(defun mu4e~set-sent-handler-message-sent-hook-fn () + ;; mu4e~compose-mark-after-sending + (setq mu4e-sent-func 'mu4e-sent-handler) + (mu4e~proc-sent (buffer-file-name))) + +(defun mu4e-send-harden-newlines () + "Set the hard property to all newlines." + (save-excursion + (goto-char (point-min)) + (while (search-forward "\n" nil t) + (put-text-property (1- (point)) (point) 'hard t)))) + +(defconst mu4e~compose-buffer-max-name-length 30 + "Maximum length of the mu4e-send-buffer-name.") + +(defun mu4e~compose-set-friendly-buffer-name (&optional compose-type) + "Set some user-friendly buffer name based on the COMPOSE-TYPE." + (let* ((subj (message-field-value "subject")) + (subj (unless (and subj (string-match "^[:blank:]*$" subj)) subj)) + (str (or subj + (cl-case compose-type + (reply "*reply*") + (forward "*forward*") + (otherwise "*draft*"))))) + (rename-buffer (generate-new-buffer-name + (truncate-string-to-width str mu4e~compose-buffer-max-name-length) + (buffer-name))))) + +(defun mu4e-compose-crypto-message (parent compose-type) + "Possibly encrypt or sign a message based on PARENT and COMPOSE-TYPE. +See `mu4e-compose-crypto-policy' for more details." + (let* ((encrypted-p + (and parent (memq 'encrypted (mu4e-message-field parent :flags)))) + (encrypt + (or (memq 'encrypt-all-messages mu4e-compose-crypto-policy) + ;; new messages + (and (memq 'encrypt-new-messages mu4e-compose-crypto-policy) + (eq compose-type 'new)) + ;; forwarded messages + (and (eq compose-type 'forward) + (memq 'encrypt-forwarded-messages mu4e-compose-crypto-policy)) + ;; edited messages + (and (eq compose-type 'edit) + (memq 'encrypt-edited-messages mu4e-compose-crypto-policy)) + ;; all replies + (and (eq compose-type 'reply) + (memq 'encrypt-all-replies mu4e-compose-crypto-policy)) + ;; plain replies + (and (eq compose-type 'reply) (not encrypted-p) + (memq 'encrypt-plain-replies mu4e-compose-crypto-policy)) + ;; encrypted replies + (and (eq compose-type 'reply) encrypted-p + (memq 'encrypt-encrypted-replies mu4e-compose-crypto-policy)))) + (sign + (or (memq 'sign-all-messages mu4e-compose-crypto-policy) + ;; new messages + (and (eq compose-type 'new) + (memq 'sign-new-messages mu4e-compose-crypto-policy)) + ;; forwarded messages + (and (eq compose-type 'forward) + (memq 'sign-forwarded-messages mu4e-compose-crypto-policy)) + ;; edited messages + (and (eq compose-type 'edit) + (memq 'sign-edited-messages mu4e-compose-crypto-policy)) + ;; all replies + (and (eq compose-type 'reply) + (memq 'sign-all-replies mu4e-compose-crypto-policy)) + ;; plain replies + (and (eq compose-type 'reply) (not encrypted-p) + (memq 'sign-plain-replies mu4e-compose-crypto-policy)) + ;; encrypted replies + (and (eq compose-type 'reply) encrypted-p + (memq 'sign-encrypted-replies mu4e-compose-crypto-policy))))) + (cond ((and sign encrypt) + (mml-secure-message-sign-encrypt)) + (sign (mml-secure-message-sign)) + (encrypt (mml-secure-message-encrypt))))) + +(cl-defun mu4e~compose-handler (compose-type &optional original-msg includes + switch-function) + "Create a new draft message, or open an existing one. + +COMPOSE-TYPE determines the kind of message to compose and is a +symbol, either `reply', `forward', `edit', `resend' `new'. `edit' +is for editing existing (draft) messages. When COMPOSE-TYPE is +`reply' or `forward', MSG should be a message plist. If +COMPOSE-TYPE is `new', ORIGINAL-MSG should be nil. + +Optionally (when forwarding, replying) ORIGINAL-MSG is the original +message we will forward / reply to. + +Optionally (when inline forwarding) INCLUDES contains a list of + (:file-name :mime-type + :description :disposition ) +or + (:buffer-name :mime-type + :description :disposition ) +for the attachments to include; file-name refers to +a file which our backend has conveniently saved for us (as a +tempfile). The properties :mime-type, :description and :disposition +are optional." + + ;; Run the hooks defined for `mu4e-compose-pre-hook'. If compose-type is + ;; `reply', `forward' or `edit', `mu4e-compose-parent-message' points to the + ;; message being forwarded or replied to, otherwise it is nil. + (set (make-local-variable 'mu4e-compose-parent-message) original-msg) + (put 'mu4e-compose-parent-message 'permanent-local t) + ;; remember the compose-type + (set (make-local-variable 'mu4e-compose-type) compose-type) + (put 'mu4e-compose-type 'permanent-local t) + ;; maybe switch the context + (mu4e~context-autoswitch mu4e-compose-parent-message + mu4e-compose-context-policy) + (run-hooks 'mu4e-compose-pre-hook) + + ;; this opens (or re-opens) a messages with all the basic headers set. + (let ((winconf (current-window-configuration))) + (condition-case nil + (mu4e-draft-open compose-type original-msg switch-function) + (quit (set-window-configuration winconf) + (mu4e-message "Operation aborted") + (cl-return-from mu4e~compose-handler)))) + ;; insert mail-header-separator, which is needed by message mode to separate + ;; headers and body. will be removed before saving to disk + (mu4e~draft-insert-mail-header-separator) + + ;; maybe encrypt/sign replies + (let ((mu4e-compose-crypto-policy ; backwards compatibility + (append + (cl-case mu4e-compose-crypto-reply-encrypted-policy + (sign '(sign-encrypted-replies)) + (encrypt '(encrypt-encrypted-replies)) + (sign-and-encrypt + '(sign-encrypted-replies encrypt-encrypted-replies))) + (cl-case mu4e-compose-crypto-reply-plain-policy + (sign '(sign-plain-replies)) + (encrypt '(encrypt-plain-replies)) + (sign-and-encrypt + '(sign-plain-replies encrypt-plain-replies))) + mu4e-compose-crypto-policy))) + (mu4e-compose-crypto-message original-msg compose-type)) + + ;; include files -- e.g. when inline forwarding a message with + ;; attachments, we take those from the original. + (save-excursion + (goto-char (point-max)) ;; put attachments at the end + + (if (and (eq compose-type 'forward) mu4e-compose-forward-as-attachment) + (mu4e-compose-attach-message original-msg) + (dolist (att includes) + (let ((file-name (plist-get att :file-name)) + (mime (plist-get att :mime-type)) + (description (plist-get att :description)) + (disposition (plist-get att :disposition))) + (if file-name + (mml-attach-file file-name mime description disposition) + (mml-attach-buffer (plist-get att :buffer-name) + mime description disposition)))))) + + (mu4e~compose-set-friendly-buffer-name compose-type) + + ;; now jump to some useful positions, and start writing that mail! + (if (member compose-type '(new forward)) + (message-goto-to) + ;; otherwise, it depends... + (cl-case message-cite-reply-position + ((above traditional) + (message-goto-body)) + (t + (when (message-goto-signature) + (forward-line -2))))) + + ;; bind to `mu4e-compose-parent-message' of compose buffer + (set (make-local-variable 'mu4e-compose-parent-message) original-msg) + (put 'mu4e-compose-parent-message 'permanent-local t) + ;; set mu4e-compose-type once more for this buffer, + (set (make-local-variable 'mu4e-compose-type) compose-type) + (put 'mu4e-compose-type 'permanent-local t) + + ;; hide some headers + (mu4e~compose-hide-headers) + ;; switch on the mode + (mu4e-compose-mode) + ;; don't allow undoing anything before this. + (setq buffer-undo-list nil) + + (when mu4e-compose-in-new-frame + ;; make sure to close the frame when we're done with the message these are + ;; all buffer-local; + (push 'delete-frame message-exit-actions) + (push 'delete-frame message-postpone-actions)) + + ;; buffer is not user-modified yet + (set-buffer-modified-p nil)) + +(defun mu4e~switch-back-to-mu4e-buffer () + "Try to go back to some previous buffer, in the order view->headers->main." + (unless (eq mu4e-split-view 'single-window) + (if (buffer-live-p (mu4e-get-view-buffer)) + (switch-to-buffer (mu4e-get-view-buffer)) + (if (buffer-live-p (mu4e-get-headers-buffer)) + (switch-to-buffer (mu4e-get-headers-buffer)) + ;; if all else fails, back to the main view + (when (fboundp 'mu4e) (mu4e)))))) + +(defun mu4e-compose-context-switch (&optional force name) + "Change the context for the current draft message. + +Same as `mu4e-context-switch' but does two things after switching +when the buffer is in `mu4e-compose-mode': +- Changes the \"From\" field to the email address of the new context +- Moves the current message to the draft folder of the new context" + (interactive "P") + (if (derived-mode-p 'mu4e-compose-mode) + (let ((old-context (mu4e-context-current)) + (has-file (file-exists-p (buffer-file-name)))) + (unless (and name (not force) (eq old-context name)) + (when (or (not has-file) + (not (buffer-modified-p)) + (y-or-n-p "Draft must be saved before switching context. Save?")) + (unless (and (not force) (eq old-context (mu4e-context-switch nil name))) + ;; Change From field to user-mail-address + (message-replace-header "From" (or (mu4e~draft-from-construct) "")) + ;; Move message to mu4e-draft-folder + (if has-file + (progn (save-buffer) + (let ((msg-id (message-fetch-field "Message-ID")) + (buf (current-buffer))) + ;; Remove the <> + (when (and msg-id (string-match "<\\(.*\\)>" msg-id)) + (save-window-excursion + (mu4e~proc-move (match-string 1 msg-id) mu4e-drafts-folder nil t) + (kill-buffer buf))))) ;; Kill previous buffer which points to wrong file + ;; No file, just change the buffer file name + (setq buffer-file-name + (format "%s/%s/cur/%s" + (mu4e-root-maildir) (mu4e-get-drafts-folder) + (file-name-nondirectory (buffer-file-name))))))))) + ;; Just do the standad switch + (mu4e-context-switch force name))) + +(defun mu4e-sent-handler (docid path) + "Handler called with DOCID and PATH for the just-sent message. +For Forwarded ('Passed') and Replied messages, try to set the +appropriate flag at the message forwarded or replied-to." + (mu4e~compose-set-parent-flag path) + (when (file-exists-p path) ;; maybe the draft was not saved at all + (mu4e~proc-remove docid)) + ;; kill any remaining buffers for the draft file, or they will hang around... + ;; this seems a bit hamfisted... + (when message-kill-buffer-on-exit + (dolist (buf (buffer-list)) + (and (buffer-file-name buf) + (string= (buffer-file-name buf) path) + (kill-buffer buf)))) + (mu4e~switch-back-to-mu4e-buffer) + (mu4e-message "Message sent")) + +(defun mu4e-message-kill-buffer () + "Wrapper around `message-kill-buffer'. +It restores mu4e window layout after killing the compose-buffer." + (interactive) + (let ((current-buffer (current-buffer))) + (message-kill-buffer) + ;; Compose buffer killed + (when (not (equal current-buffer (current-buffer))) + ;; Restore mu4e + (if mu4e-compose-in-new-frame + (delete-frame) + (mu4e~switch-back-to-mu4e-buffer))))) + +(defun mu4e~compose-set-parent-flag (path) + "Set flags for replied-t and forwarded for the message at PATH. +That is, set the 'replied' \"R\" flag on messages we replied to, +and the 'passed' \"F\" flag on message we have forwarded. + +If a message has an 'in-reply-to' header, it is considered a reply +to the message with the corresponding message id. If it does not +have an 'in-reply-to' header, but does have a 'references' header, +it is considered to be a forward message for the message +corresponding with the /last/ message-id in the references header. + +Now, if the message has been determined to be either a forwarded +message or a reply, we instruct the server to update that message +with resp. the 'P' (passed) flag for a forwarded message, or the +'R' flag for a replied message. The original messages are also +marked as Seen. + +Function assumes that it's executed in the context of the message +buffer." + (let ((buf (find-file-noselect path))) + (when buf + (with-current-buffer buf + (message-narrow-to-headers-or-head) + (let ((in-reply-to (message-fetch-field "in-reply-to")) + (forwarded-from) + (references (message-fetch-field "references"))) + (unless in-reply-to + (when references + (with-temp-buffer ;; inspired by `message-shorten-references'. + (insert references) + (goto-char (point-min)) + (let ((refs)) + (while (re-search-forward "<[^ <]+@[^ <]+>" nil t) + (push (match-string 0) refs)) + ;; the last will be the first + (setq forwarded-from (cl-first refs)))))) + ;; remove the <> + (when (and in-reply-to (string-match "<\\(.*\\)>" in-reply-to)) + (mu4e~proc-move (match-string 1 in-reply-to) nil "+R-N")) + (when (and forwarded-from (string-match "<\\(.*\\)>" forwarded-from)) + (mu4e~proc-move (match-string 1 forwarded-from) nil "+P-N"))))))) + +(defun mu4e-compose (compose-type) + "Start composing a message of COMPOSE-TYPE. +COMPOSE-TYPE is a symbol, one of `reply', `forward', `edit', +`resend' `new'. All but `new' take the message at point as input. +Symbol `edit' is only allowed for draft messages." + (let ((msg (mu4e-message-at-point 'noerror))) + ;; some sanity checks + (unless (or msg (eq compose-type 'new)) + (mu4e-warn "No message at point")) + (unless (member compose-type '(reply forward edit resend new)) + (mu4e-error "Invalid compose type '%S'" compose-type)) + (when (and (eq compose-type 'edit) + (not (member 'draft (mu4e-message-field msg :flags)))) + (mu4e-warn "Editing is only allowed for draft messages")) + + ;; 'new is special, since it takes no existing message as arg; therefore, we + ;; don't need to involve the backend, and call the handler *directly* + (if (eq compose-type 'new) + (mu4e~compose-handler 'new) + ;; otherwise, we need the doc-id + (let* ((docid (mu4e-message-field msg :docid)) + ;; decrypt (or not), based on `mu4e-decryption-policy'. + (decrypt + (and (member 'encrypted (mu4e-message-field msg :flags)) + (if (eq mu4e-decryption-policy 'ask) + (yes-or-no-p (mu4e-format "Decrypt message?")) + mu4e-decryption-policy)))) + ;; if there's a visible view window, select that before starting + ;; composing a new message, so that one will be replaced by the compose + ;; window. The 10-or-so line headers buffer is not a good place to write + ;; it... + (unless (eq mu4e-split-view 'single-window) + (let ((viewwin (get-buffer-window (mu4e-get-view-buffer)))) + (when (window-live-p viewwin) + (select-window viewwin)))) + ;; talk to the backend + (mu4e~proc-compose compose-type decrypt docid))))) + +(defun mu4e-compose-reply () + "Compose a reply for the message at point in the headers buffer." + (interactive) + (mu4e-compose 'reply)) + +(defun mu4e-compose-forward () + "Forward the message at point in the headers buffer." + (interactive) + (mu4e-compose 'forward)) + +(defun mu4e-compose-edit () + "Edit the draft message at point in the headers buffer. +This is only possible if the message at point is, in fact, a +draft message." + (interactive) + (mu4e-compose 'edit)) + +(defun mu4e-compose-resend () + "Resend the message at point in the headers buffer." + (interactive) + (mu4e-compose 'resend)) + +(defun mu4e-compose-new () + "Start writing a new message." + (interactive) + (mu4e-compose 'new)) + + +;;; Compose Mail +;; mu4e-compose-func and mu4e-send-func are wrappers so we can set ourselves +;; as default emacs mailer (define-mail-user-agent etc.) + +;;;###autoload +(defun mu4e~compose-mail (&optional to subject other-headers _continue + switch-function yank-action _send-actions _return-action) + "This is mu4e's implementation of `compose-mail'. +Quoting its docstring: +Start composing a mail message to send. +This uses the user’s chosen mail composition package +as selected with the variable ‘mail-user-agent’. +The optional arguments TO and SUBJECT specify recipients +and the initial Subject field, respectively. + +OTHER-HEADERS is an alist specifying additional +header fields. Elements look like (HEADER . VALUE) where both +HEADER and VALUE are strings. + +CONTINUE, if non-nil, says to continue editing a message already +being composed. Interactively, CONTINUE is the prefix argument. + +SWITCH-FUNCTION, if non-nil, is a function to use to +switch to and display the buffer used for mail composition. + +YANK-ACTION, if non-nil, is an action to perform, if and when necessary, +to insert the raw text of the message being replied to. +It has the form (FUNCTION . ARGS). The user agent will apply +FUNCTION to ARGS, to insert the raw text of the original message. +\(The user agent will also run ‘mail-citation-hook’, *after* the +original text has been inserted in this way.) + +SEND-ACTIONS is a list of actions to call when the message is sent. +Each action has the form (FUNCTION . ARGS). + +RETURN-ACTION, if non-nil, is an action for returning to the +caller. It has the form (FUNCTION . ARGS). The function is +called after the mail has been sent or put aside, and the mail +buffer buried." + (unless (mu4e-running-p) + (mu4e~start)) + + ;; create a new draft message 'resetting' (as below) is not actually needed in this case, but + ;; let's prepare for the re-edit case as well + (mu4e~compose-handler 'new nil nil switch-function) + + (when (message-goto-to) ;; reset to-address, if needed + (message-delete-line)) + (message-add-header (concat "To: " to "\n")) + + (when (message-goto-subject) ;; reset subject, if needed + (message-delete-line)) + (message-add-header (concat "Subject: " subject "\n")) + + ;; add any other headers specified + (when other-headers + (dolist (h other-headers other-headers) + (if (symbolp (car h)) (setcar h (symbol-name (car h)))) + (message-add-header (concat (capitalize (car h)) ": " (cdr h) "\n" )) + )) + + ;; yank message + (if (bufferp yank-action) + (list 'insert-buffer yank-action) + yank-action) + + ;; try to put the user at some reasonable spot... + (if (not to) + (message-goto-to) + (if (not subject) + (message-goto-subject) + (message-goto-body)))) + +;; happily, we can re-use most things from message mode +;;;###autoload +(define-mail-user-agent 'mu4e-user-agent + 'mu4e~compose-mail + 'message-send-and-exit + 'message-kill-buffer + 'message-send-hook) +;; Without this `mail-user-agent' cannot be set to `mu4e-user-agent' +;; through customize, as the custom type expects a function. Not +;; sure whether this function is actually ever used; if it is then +;; returning the symbol is probably the correct thing to do, as other +;; such functions suggest. +(defun mu4e-user-agent () + "Return the `mu4e-user-agent' symbol." + 'mu4e-user-agent) + +;;; Go to bottom / top + +(defun mu4e-compose-goto-top (&optional arg) + "Go to the beginning of the message or buffer. +Go to the beginning of the message or, if already there, go to the +beginning of the buffer. + +Push mark at previous position, unless either a \\[universal-argument] prefix +is supplied, or Transient Mark mode is enabled and the mark is active." + (interactive "P") + (or arg + (region-active-p) + (push-mark)) + (let ((old-position (point))) + (message-goto-body) + (when (equal (point) old-position) + (goto-char (point-min))))) + +(define-key mu4e-compose-mode-map + (vector 'remap 'beginning-of-buffer) 'mu4e-compose-goto-top) + +(defun mu4e-compose-goto-bottom (&optional arg) + "Go to the end of the message or buffer. +Go to the end of the message (before signature) or, if already there, go to the +end of the buffer. + +Push mark at previous position, unless either a \\[universal-argument] prefix +is supplied, or Transient Mark mode is enabled and the mark is active." + (interactive "P") + (or arg + (region-active-p) + (push-mark)) + (let ((old-position (point)) + (message-position (save-excursion (message-goto-body) (point)))) + (goto-char (point-max)) + (when (re-search-backward message-signature-separator message-position t) + (forward-line -1)) + (when (equal (point) old-position) + (goto-char (point-max))))) + +(define-key mu4e-compose-mode-map + (vector 'remap 'end-of-buffer) 'mu4e-compose-goto-bottom) + +;;; _ +(provide 'mu4e-compose) +;;; mu4e-compose.el ends here diff --git a/elisp/mu4e/mu4e-context.el b/elisp/mu4e/mu4e-context.el new file mode 100644 index 0000000..afecb4a --- /dev/null +++ b/elisp/mu4e/mu4e-context.el @@ -0,0 +1,183 @@ +;;; mu4e-context.el -- part of mu4e, the mu mail user agent -*- lexical-binding: t -*- + +;; Copyright (C) 2015-2021 Dirk-Jan C. Binnema + +;; Author: Dirk-Jan C. Binnema +;; Maintainer: Dirk-Jan C. Binnema + +;; This file is not part of GNU Emacs. + +;; mu4e is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; mu4e is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with mu4e. If not, see . + +;;; Commentary: + +;; A mu4e 'context' is a set of variable-settings and functions, which can be +;; used e.g. to switch between accounts. + +;;; Code: + +(require 'cl-lib) +(require 'mu4e-utils) + +(defvar smtpmail-smtp-user) +(defvar mu4e-view-date-format) + +(defvar mu4e-contexts nil "The list of `mu4e-context' objects +describing mu4e's contexts.") + +(defvar mu4e-context-changed-hook nil + "Hook run just *after* the context changed.") + +(defvar mu4e~context-current nil + "The current context; for internal use. Use + `mu4e-context-switch' to change it.") + +(defun mu4e-context-current (&optional output) + "Get the currently active context, or nil if there is none. +When OUTPUT is non-nil, echo the name of the current context or +none." + (interactive "p") + (let ((ctx mu4e~context-current)) + (when output + (mu4e-message "Current context: %s" + (if ctx (mu4e-context-name ctx) ""))) + ctx)) + +(defun mu4e-context-label () + "Propertized string with the current context name, or \"\" if + there is none." + (if (mu4e-context-current) + (concat "[" (propertize (mu4e~quote-for-modeline + (mu4e-context-name (mu4e-context-current))) + 'face 'mu4e-context-face) "]") "")) + +(cl-defstruct mu4e-context + "A mu4e context object with the following members: +- `name': the name of the context, eg. \"Work\" or \"Private\". +- `enter-func': a parameterless function invoked when entering + this context, or nil +- `leave-func':a parameterless function invoked when leaving this + context, or nil +- `match-func': a function called when composing a new message, + that takes a message plist for the message replied to or + forwarded, and nil otherwise. Before composing a new message, + `mu4e' switches to the first context for which `match-func' + returns t. +- `vars': variables to set when entering context." + name ;; name of the context, e.g. "work" + (enter-func nil) ;; function invoked when entering the context + (leave-func nil) ;; function invoked when leaving the context + (match-func nil) ;; function that takes a msg-proplist, and return t + ;; if it matches, nil otherwise + vars) ;; alist of variables. + + +(defun mu4e~context-ask-user (prompt) + "Let user choose some context based on its name." + (when mu4e-contexts + (let* ((names (cl-map 'list (lambda (context) + (cons (mu4e-context-name context) context)) + mu4e-contexts)) + (context (mu4e-read-option prompt names))) + (or context (mu4e-error "No such context"))))) + +(defun mu4e-context-switch (&optional force name) + "Switch context to a context with NAME which is part of +`mu4e-contexts'; if NAME is nil, query user. + +If the new context is the same and the current context, only +switch (run associated functions) when prefix argument FORCE is +non-nil." + (interactive "P") + (unless mu4e-contexts + (mu4e-error "No contexts defined")) + (let* ((names (cl-map 'list (lambda (context) + (cons (mu4e-context-name context) context)) + mu4e-contexts)) + (context + (if name + (cdr-safe (assoc name names)) + (mu4e~context-ask-user "Switch to context: ")))) + (unless context (mu4e-error "No such context")) + ;; if new context is same as old one one switch with FORCE is set. + (when (or force (not (eq context (mu4e-context-current)))) + (when (and (mu4e-context-current) + (mu4e-context-leave-func mu4e~context-current)) + (funcall (mu4e-context-leave-func mu4e~context-current))) + ;; enter the new context + (when (mu4e-context-enter-func context) + (funcall (mu4e-context-enter-func context))) + (when (mu4e-context-vars context) + (mapc (lambda (cell) + (set (car cell) (cdr cell))) + (mu4e-context-vars context))) + (setq mu4e~context-current context) + + (run-hooks 'mu4e-context-changed-hook) + (mu4e-message "Switched context to %s" (mu4e-context-name context)) + (force-mode-line-update)) + context)) + +(defun mu4e~context-autoswitch (&optional msg policy) + "When contexts are defined but there is no context yet, switch +to the first whose :match-func return non-nil. If none of them +match, return the first. For MSG and POLICY, see `mu4e-context-determine'." + (when mu4e-contexts + (let ((context (mu4e-context-determine msg policy))) + (when context (mu4e-context-switch + nil (mu4e-context-name context)))))) + +(defun mu4e-context-determine (msg &optional policy) + "Return the first context with a match-func that returns t. MSG +points to the plist for the message replied to or forwarded, or +nil if there is no such MSG; similar to what +`mu4e-compose-pre-hook' does. + +POLICY specifies how to do the determination. If POLICY is +'always-ask, we ask the user unconditionally. + +In all other cases, if any context matches (using its match +function), this context is returned. If none of the contexts +match, POLICY determines what to do: + +- pick-first: pick the first of the contexts available +- ask: ask the user +- ask-if-none: ask if there is no context yet +- otherwise, return nil. Effectively, this leaves the current context as it is." + (when mu4e-contexts + (if (eq policy 'always-ask) + (mu4e~context-ask-user "Select context: ") + (or ;; is there a matching one? + (cl-find-if (lambda (context) + (when (mu4e-context-match-func context) + (funcall (mu4e-context-match-func context) msg))) + mu4e-contexts) + ;; no context found yet; consult policy + (cl-case policy + (pick-first (car mu4e-contexts)) + (ask (mu4e~context-ask-user "Select context: ")) + (ask-if-none (or (mu4e-context-current) + (mu4e~context-ask-user "Select context: "))) + (otherwise nil)))))) + +(defun mu4e-context-in-modeline () + "Display the mu4e-context (if any) in a (buffer-specific) +global-mode-line." + (add-to-list + (make-local-variable 'global-mode-string) + '(:eval (mu4e-context-label)))) + +;;; _ +(provide 'mu4e-context) +;;; mu4e-context.el ends here diff --git a/elisp/mu4e/mu4e-contrib.el b/elisp/mu4e/mu4e-contrib.el new file mode 100644 index 0000000..c784373 --- /dev/null +++ b/elisp/mu4e/mu4e-contrib.el @@ -0,0 +1,224 @@ +;;; mu4e-contrib.el -- part of mu4e, the mu mail user agent -*- lexical-binding: t -*- + +;; Copyright (C) 2013-2021 Dirk-Jan C. Binnema + +;; This file is not part of GNU Emacs. + +;; mu4e is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; mu4e is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with mu4e. If not, see . + +;;; Commentary: + +;; Some user-contributed functions for mu4e + +;;; Code: + +(require 'mu4e-headers) +(require 'mu4e-view) +(require 'bookmark) +(require 'eshell) + +;; Contributed by sabof +(defvar bookmark-make-record-function) + +;;; Various simple commands + +(defun mu4e-headers-mark-all-unread-read () + "Put a ! \(read) mark on all visible unread messages." + (interactive) + (mu4e-headers-mark-for-each-if + (cons 'read nil) + (lambda (msg _param) + (memq 'unread (mu4e-msg-field msg :flags))))) + +(defun mu4e-headers-flag-all-read () + "Flag all visible messages as \"read\"." + (interactive) + (mu4e-headers-mark-all-unread-read) + (mu4e-mark-execute-all t)) + +(defun mu4e-headers-mark-all () + "Mark all messages within current query results and ask user to execute which action." + (interactive) + (mu4e-headers-mark-for-each-if + (cons 'something nil) + (lambda (_msg _param) t)) + (mu4e-mark-execute-all)) + +;;; Bookmark handlers +;; +;; Allow bookmarking a mu4e buffer in regular emacs bookmarks. + +(defun mu4e~view-set-bookmark-make-record-fn () + (set (make-local-variable 'bookmark-make-record-function) + 'mu4e-view-bookmark-make-record)) + +(defun mu4e~headers-set-bookmark-make-record-fn () + (set (make-local-variable 'bookmark-make-record-function) + 'mu4e-view-bookmark-make-record)) + +;; Probably this can be moved to mu4e-view.el. +(add-hook 'mu4e-view-mode-hook #'mu4e~view-set-bookmark-make-record-fn) +;; And this can be moved to mu4e-headers.el. +(add-hook 'mu4e-headers-mode-hook #'mu4e~headers-set-bookmark-make-record-fn) + +(defun mu4e-view-bookmark-make-record () + "Make a bookmark entry for a mu4e buffer. Note that this is an +emacs bookmark, not to be confused with `mu4e-bookmarks'." + (let* ((msg (mu4e-message-at-point)) + (maildir (plist-get msg :maildir)) + (date (format-time-string "%Y%m%d" (plist-get msg :date))) + (query (format "maildir:%s date:%s" maildir date)) + (docid (plist-get msg :docid)) + (mode (symbol-name major-mode)) + (subject (or (plist-get msg :subject) "No subject"))) + `(,subject + ,@(bookmark-make-record-default 'no-file 'no-context) + (location . (,query . ,docid)) + (mode . ,mode) + (handler . mu4e-bookmark-jump)))) + +(defun mu4e-bookmark-jump (bookmark) + "Handler function for record returned by `mu4e-view-bookmark-make-record'. +BOOKMARK is a bookmark name or a bookmark record." + (let* ((path (bookmark-prop-get bookmark 'location)) + (mode (bookmark-prop-get bookmark 'mode)) + (docid (cdr path)) + (query (car path))) + (call-interactively 'mu4e) + (mu4e-headers-search query) + (sit-for 0.5) + (mu4e~headers-goto-docid docid) + (mu4e~headers-highlight docid) + (unless (string= mode "mu4e-headers-mode") + (call-interactively 'mu4e-headers-view-message) + (run-with-timer 0.1 nil + (lambda (bmk) + (bookmark-default-handler + `("" (buffer . ,(current-buffer)) . + ,(bookmark-get-bookmark-record bmk)))) + bookmark)))) + +;;; Bogofilter/SpamAssassin +;; +;; Support for handling spam with Bogofilter with the possibility +;; to define it for SpamAssassin, contributed by Gour. +;; +;; To add the actions to the menu, you can use something like: +;; +;; (add-to-list 'mu4e-headers-actions +;; '("sMark as spam" . mu4e-register-msg-as-spam) t) +;; (add-to-list 'mu4e-headers-actions +;; '("hMark as ham" . mu4e-register-msg-as-ham) t) + +(defvar mu4e-register-as-spam-cmd nil + "Command for invoking spam processor to register message as spam, +for example for bogofilter, use \"/usr/bin/bogofilter -Ns < %s\" ") + +(defvar mu4e-register-as-ham-cmd nil + "Command for invoking spam processor to register message as ham. +For example for bogofile, use \"/usr/bin/bogofilter -Sn < %s\"") + +(defun mu4e-register-msg-as-spam (msg) + "Mark message as spam." + (interactive) + (let* ((path (shell-quote-argument (mu4e-message-field msg :path))) + (command (format mu4e-register-as-spam-cmd path))) ;; re-register msg as spam + (shell-command command)) + (mu4e-mark-at-point 'delete nil)) + +(defun mu4e-register-msg-as-ham (msg) + "Mark message as ham." + (interactive) + (let* ((path (shell-quote-argument(mu4e-message-field msg :path))) + (command (format mu4e-register-as-ham-cmd path))) ;; re-register msg as ham + (shell-command command)) + (mu4e-mark-at-point 'something nil)) + +;; (add-to-list 'mu4e-view-actions +;; '("sMark as spam" . mu4e-view-register-msg-as-spam) t) +;; (add-to-list 'mu4e-view-actions +;; '("hMark as ham" . mu4e-view-register-msg-as-ham) t) + +(defun mu4e-view-register-msg-as-spam (msg) + "Mark message as spam (view mode)." + (interactive) + (let* ((path (shell-quote-argument (mu4e-message-field msg :path))) + (command (format mu4e-register-as-spam-cmd path))) + (shell-command command)) + (mu4e-view-mark-for-delete)) + +(defun mu4e-view-register-msg-as-ham (msg) + "Mark message as ham (view mode)." + (interactive) + (let* ((path (shell-quote-argument(mu4e-message-field msg :path))) + (command (format mu4e-register-as-ham-cmd path))) + (shell-command command)) + (mu4e-view-mark-for-something)) + +;;; Eshell functions +;; +;; Code for `gnus-dired-attached' modified to run from eshell, +;; allowing files to be attached to an email via mu4e using the +;; eshell. Does not depend on gnus. + +(defun eshell/mu4e-attach (&rest args) + "Attach files to a mu4e message using eshell. If no mu4e +buffers found, compose a new message and then attach the file." + (let ((destination nil) + (files-str nil) + (bufs nil) + ;; Remove directories from the list + (files-to-attach + (delq nil (mapcar + (lambda (f) (if (or (not (file-exists-p f)) (file-directory-p f)) + nil + (expand-file-name f))) + (eshell-flatten-list (reverse args)))))) + ;; warn if user tries to attach without any files marked + (if (null files-to-attach) + (error "No files to attach") + (setq files-str + (mapconcat + (lambda (f) (file-name-nondirectory f)) + files-to-attach ", ")) + (setq bufs (mu4e~active-composition-buffers)) + ;; set up destination mail composition buffer + (if (and bufs + (y-or-n-p "Attach files to existing mail composition buffer? ")) + (setq destination + (if (= (length bufs) 1) + (get-buffer (car bufs)) + (let ((prompt (mu4e-format "%s" "Attach to buffer"))) + (substring-no-properties + (funcall mu4e-completing-read-function prompt + bufs))))) + ;; setup a new mail composition buffer + (if (y-or-n-p "Compose new mail and attach this file? ") + (progn (mu4e-compose-new) + (setq destination (current-buffer))))) + ;; if buffer was found, set buffer to destination buffer, and attach files + (if (not (eq destination 'nil)) + (progn (set-buffer destination) + (goto-char (point-max)) ; attach at end of buffer + (while files-to-attach + (mml-attach-file (car files-to-attach) + (or (mm-default-file-encoding (car files-to-attach)) + "application/octet-stream") nil) + (setq files-to-attach (cdr files-to-attach))) + (message "Attached file(s) %s" files-str)) + (message "No buffer to attach file to."))))) + +;;; _ +(provide 'mu4e-contrib) +;;; mu4e-contrib.el ends here diff --git a/elisp/mu4e/mu4e-draft.el b/elisp/mu4e/mu4e-draft.el new file mode 100644 index 0000000..d68d3f1 --- /dev/null +++ b/elisp/mu4e/mu4e-draft.el @@ -0,0 +1,604 @@ +;;; mu4e-draft.el -- part of mu4e, the mu mail user agent for emacs -*- lexical-binding: t -*- +;; +;; Copyright (C) 2011-2020 Dirk-Jan C. Binnema + +;; Author: Dirk-Jan C. Binnema +;; Maintainer: Dirk-Jan C. Binnema + +;; This file is not part of GNU Emacs. + +;; mu4e is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; mu4e is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with mu4e. If not, see . + +;;; Commentary: + +;; In this file, various functions to create draft messages + +;;; Code: + +(require 'cl-lib) +(require 'mu4e-vars) +(require 'mu4e-utils) +(require 'mu4e-message) +(require 'message) ;; mail-header-separator + +;;; Options + +(defcustom mu4e-compose-dont-reply-to-self nil + "If non-nil, don't include self. +(as decided by `mu4e-personal-address-p')" + :type 'boolean + :group 'mu4e-compose) + +(defcustom mu4e-compose-cite-function + (or message-cite-function 'message-cite-original-without-signature) + "The function for citing message in replies and forwards. +This is the mu4e-specific version of +`message-cite-function'." + :type 'function + :group 'mu4e-compose) + +(defcustom mu4e-compose-signature + (or message-signature "Sent with my mu4e") + "The message signature. +\(i.e. the blob at the bottom of messages). This is the +mu4e-specific version of `message-signature'." + :type '(choice string + (const :tag "None" nil) + (const :tag "Contents of signature file" t) + function sexp) + :risky t + :group 'mu4e-compose) + +(defcustom mu4e-compose-signature-auto-include t + "Whether to automatically include a message-signature." + :type 'boolean + :group 'mu4e-compose) + +(make-obsolete-variable 'mu4e-compose-auto-include-date + "This is done unconditionally now" "1.3.5") + +(defcustom mu4e-compose-in-new-frame nil + "Whether to compose messages in a new frame." + :type 'boolean + :group 'mu4e-compose) + +(defvar mu4e-user-agent-string + (format "mu4e %s; emacs %s" mu4e-mu-version emacs-version) + "The User-Agent string for mu4e, or nil.") + +(defvar mu4e-view-date-format) + +(defun mu4e~draft-cite-original (msg) + "Return a cited version of the original message MSG as a plist. +This function uses `mu4e-compose-cite-function', and as such all +its settings apply." + (with-temp-buffer + (when (fboundp 'mu4e-view-message-text) ;; keep bytecompiler happy + (let ((mu4e-view-date-format "%Y-%m-%dT%T%z")) + (insert (mu4e-view-message-text msg))) + (message-yank-original) + (goto-char (point-min)) + (push-mark (point-max)) + ;; set the the signature separator to 'loose', since in the real world, + ;; many message don't follow the standard... + (let ((message-signature-separator "^-- *$") + (message-signature-insert-empty-line t)) + (funcall mu4e-compose-cite-function)) + (pop-mark) + (goto-char (point-min)) + (buffer-string)))) + +(defun mu4e~draft-header (hdr val) + "Return a header line of the form \"HDR: VAL\". +If VAL is nil, return nil." + ;; note: the propertize here is currently useless, since gnus sets its own + ;; later. + (when val (format "%s: %s\n" + (propertize hdr 'face 'mu4e-header-key-face) + (propertize val 'face 'mu4e-header-value-face)))) + +(defconst mu4e~max-reference-num 21 + "Specifies the maximum number of References:. +As suggested by `message-shorten-references'.") + +(defun mu4e~shorten-1 (list cut surplus) + "Cut SURPLUS elements out of LIST. +Beginning with CUTth +one. Code borrowed from `message-shorten-1'." + (setcdr (nthcdr (- cut 2) list) + (nthcdr (+ (- cut 2) surplus 1) list))) + +(defun mu4e~draft-references-construct (msg) + "Construct the value of the References: header based on MSG. +This assumes a comma-separated string. Normally, this the concatenation of the +existing References + In-Reply-To (which may be empty, an note +that :references includes the old in-reply-to as well) and the +message-id. If the message-id is empty, returns the old +References. If both are empty, return nil." + (let* ( ;; these are the ones from the message being replied to / forwarded + (refs (mu4e-message-field msg :references)) + (msgid (mu4e-message-field msg :message-id)) + ;; now, append in + (refs (if (and msgid (not (string= msgid ""))) + (append refs (list msgid)) refs)) + ;; no doubles + (refs (cl-delete-duplicates refs :test #'equal)) + (refnum (length refs)) + (cut 2)) + ;; remove some refs when there are too many + (when (> refnum mu4e~max-reference-num) + (let ((surplus (- refnum mu4e~max-reference-num))) + (mu4e~shorten-1 refs cut surplus))) + (mapconcat (lambda (id) (format "<%s>" id)) refs " "))) + + +;;; Determine the recipient fields for new messages + +(defun mu4e~draft-recipients-list-to-string (lst) + "Convert a lst LST of address cells into a string. +This is specified as a comma-separated list of e-mail addresses. +If LST is nil, returns nil." + (when lst + (mapconcat + (lambda (addrcell) + (let ((name (car addrcell)) + (email (cdr addrcell))) + (if name + (format "%s <%s>" (mu4e~rfc822-quoteit name) email) + (format "%s" email)))) + lst ", "))) + +(defun mu4e~draft-address-cell-equal (cell1 cell2) + "Return t if CELL1 and CELL2 have the same e-mail address. +The comparison is done case-insensitively. If the cells done +match return nil. CELL1 and CELL2 are cons cells of the +form (NAME . EMAIL)." + (string= + (downcase (or (cdr cell1) "")) + (downcase (or (cdr cell2) "")))) + + +(defun mu4e~draft-create-to-lst (origmsg) + "Create a list of address for the To: in a new message. +This is based on the original message ORIGMSG. If the Reply-To +address is set, use that, otherwise use the From address. Note, +whatever was in the To: field before, goes to the Cc:-list (if +we're doing a reply-to-all). Special case: if we were the sender +of the original, we simple copy the list form the original." + (let ((reply-to + (or (plist-get origmsg :reply-to) (plist-get origmsg :from)))) + (cl-delete-duplicates reply-to :test #'mu4e~draft-address-cell-equal) + (if mu4e-compose-dont-reply-to-self + (cl-delete-if + (lambda (to-cell) + (mu4e-personal-address-p (cdr to-cell))) + reply-to) + reply-to))) + + +(defun mu4e~strip-ignored-addresses (addrs) + "Return all addresses that are not to be ignored. +I.e. return all the addresses in ADDRS not matching +`mu4e-compose-reply-ignore-address'." + (cond + ((null mu4e-compose-reply-ignore-address) + addrs) + ((functionp mu4e-compose-reply-ignore-address) + (cl-remove-if + (lambda (elt) + (funcall mu4e-compose-reply-ignore-address (cdr elt))) + addrs)) + (t + ;; regexp or list of regexps + (let* ((regexp mu4e-compose-reply-ignore-address) + (regexp (if (listp regexp) + (mapconcat (lambda (elt) (concat "\\(" elt "\\)")) + regexp "\\|") + regexp))) + (cl-remove-if + (lambda (elt) + (string-match regexp (cdr elt))) + addrs))))) + +(defun mu4e~draft-create-cc-lst (origmsg &optional reply-all include-from) + "Create a list of address for the Cc: in a new message. +This is based on the original message ORIGMSG, and whether it's a +REPLY-ALL." + (when reply-all + (let* ((cc-lst ;; get the cc-field from the original, remove dups + (cl-delete-duplicates + (append + (plist-get origmsg :to) + (plist-get origmsg :cc) + (when include-from(plist-get origmsg :from)) + (plist-get origmsg :list-post)) + :test #'mu4e~draft-address-cell-equal)) + ;; now we have the basic list, but we must remove + ;; addresses also in the To: list + (cc-lst + (cl-delete-if + (lambda (cc-cell) + (cl-find-if + (lambda (to-cell) + (mu4e~draft-address-cell-equal cc-cell to-cell)) + (mu4e~draft-create-to-lst origmsg))) + cc-lst)) + ;; remove ignored addresses + (cc-lst (mu4e~strip-ignored-addresses cc-lst)) + ;; finally, we need to remove ourselves from the cc-list + ;; unless mu4e-compose-keep-self-cc is non-nil + (cc-lst + (if (or mu4e-compose-keep-self-cc (null user-mail-address)) + cc-lst + (cl-delete-if + (lambda (cc-cell) + (mu4e-personal-address-p (cdr cc-cell))) + cc-lst)))) + cc-lst))) + +(defun mu4e~draft-recipients-construct (field origmsg &optional reply-all include-from) + "Create value (a string) for the recipient FIELD. +\(which is a symbol, :to or :cc), based on the original message ORIGMSG, +and (optionally) REPLY-ALL which indicates this is a reply-to-all +message. Return nil if there are no recipients for the particular field." + (mu4e~draft-recipients-list-to-string + (cl-case field + (:to + (mu4e~draft-create-to-lst origmsg)) + (:cc + (mu4e~draft-create-cc-lst origmsg reply-all include-from)) + (otherwise + (mu4e-error "Unsupported field"))))) + +;;; RFC2822 handling of phrases in mail-addresses +;; +;; The optional display-name contains a phrase, it sits before the +;; angle-addr as specified in RFC2822 for email-addresses in header +;; fields. Contributed by jhelberg. + +(defun mu4e~rfc822-phrase-type (ph) + "Return an atom or quoted-string for the phrase PH. +This checks for empty string first. Then quotes around the phrase +\(returning 'rfc822-quoted-string). Then whether there is a quote +inside the phrase (returning 'rfc822-containing-quote). +The reverse of the RFC atext definition is then tested. +If it matches, nil is returned, if not, it is an 'rfc822-atom, which +is returned." + (cond + ((= (length ph) 0) 'rfc822-empty) + ((= (aref ph 0) ?\") + (if (string-match "\"\\([^\"\\\n]\\|\\\\.\\|\\\\\n\\)*\"" ph) + 'rfc822-quoted-string + 'rfc822-containing-quote)) ; starts with quote, but doesn't end with one + ((string-match-p "[\"]" ph) 'rfc822-containing-quote) + ((string-match-p "[\000-\037()\*<>@,;:\\\.]+" ph) nil) + (t 'rfc822-atom))) + +(defun mu4e~rfc822-quoteit (ph) + "Quote an RFC822 phrase PH only if necessary. +Atoms and quoted strings don't need quotes. The rest do. In +case a phrase contains a quote, it will be escaped." + (let ((type (mu4e~rfc822-phrase-type ph))) + (cond + ((eq type 'rfc822-atom) ph) + ((eq type 'rfc822-quoted-string) ph) + ((eq type 'rfc822-containing-quote) + (format "\"%s\"" + (replace-regexp-in-string "\"" "\\\\\"" ph))) + (t (format "\"%s\"" ph))))) + + +(defun mu4e~draft-from-construct () + "Construct a value for the From:-field of the reply. +This is based on the variable `user-full-name' and +`user-mail-address'; if the latter is nil, function returns nil." + (when user-mail-address + (if user-full-name + (format "%s <%s>" (mu4e~rfc822-quoteit user-full-name) user-mail-address) + (format "%s" user-mail-address)))) + + +;;; Header separators + +(defun mu4e~draft-insert-mail-header-separator () + "Insert `mail-header-separator' in the first empty line of the message. +`message-mode' needs this line to know where the headers end and +the body starts. Note, in `mu4e-compose-mode', we use +`before-save-hook' and `after-save-hook' to ensure that this +separator is never written to the message file. Also see +`mu4e-remove-mail-header-separator'." + ;; we set this here explicitly, since (as it has happened) a wrong + ;; value for this (such as "") breaks address completion and other things + (set (make-local-variable 'mail-header-separator) "--text follows this line--") + (put 'mail-header-separator 'permanent-local t) + (save-excursion + ;; make sure there's not one already + (mu4e~draft-remove-mail-header-separator) + (let ((sepa (propertize mail-header-separator + 'intangible t + ;; don't make this read-only, message-mode + ;; seems to require it being writable in some cases + ;;'read-only "Can't touch this" + 'rear-nonsticky t + 'font-lock-face 'mu4e-compose-separator-face))) + (widen) + ;; search for the first empty line + (goto-char (point-min)) + (if (search-forward-regexp "^$" nil t) + (progn + (replace-match sepa) + ;; `message-narrow-to-headers` searches for a + ;; `mail-header-separator` followed by a new line. Therefore, we + ;; must insert a newline if on the last line of the buffer. + (when (= (point) (point-max)) + (insert "\n"))) + (progn ;; no empty line? then prepend one + (goto-char (point-max)) + (insert "\n" sepa)))))) + +(defun mu4e~draft-remove-mail-header-separator () + "Remove `mail-header-separator'. +We do this before saving a +file (and restore it afterwards), to ensure that the separator +never hits the disk. Also see +`mu4e~draft-insert-mail-header-separator." + (save-excursion + (widen) + (goto-char (point-min)) + ;; remove the --text follows this line-- separator + (when (search-forward-regexp (concat "^" mail-header-separator) nil t) + (let ((inhibit-read-only t)) + (replace-match ""))))) + +(defun mu4e~draft-reply-all-p (origmsg) + "Ask user whether she wants to reply to *all* recipients. +If there is just one recipient of ORIGMSG do nothing." + (let* ((recipnum + (+ (length (mu4e~draft-create-to-lst origmsg)) + (length (mu4e~draft-create-cc-lst origmsg t)))) + (response + (if (< recipnum 2) + 'all ;; with less than 2 recipients, we can reply to 'all' + (mu4e-read-option + "Reply to " + `( (,(format "all %d recipients" recipnum) . all) + ("sender only" . sender-only)))))) + (eq response 'all))) + +(defun mu4e~draft-message-filename-construct (&optional flagstr) + "Construct a randomized name for a message file with flags FLAGSTR. +It looks something like +