diffit
makepub
cvs-access
+cup-page
+2001-12-18 Josh Huber <huber@alum.wpi.edu>
+
+ * ChangeLog, todo: (oops) changed buffer-file-coding-system back
+ to coding.
+
+2001-12-18 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * make-x.bat: Ensure nonempty variable value. Reported by Frank
+ Haun <pille3000@gmx.net>.
+
+2001-12-18 01:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * ChangeLog, todo: Add `coding'.
+
+2001-12-17 Josh Huber <huber@alum.wpi.edu>
+
+ * ChangeLog: changed coding to buffer-file-coding-system
+ * todo: same
+
+2001-12-10 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * make-x.bat: Code cleanup. Fix a bug with "/copy". From Frank
+ Schmitt <ich@Frank-Schmitt.net>.
+
+2001-11-26 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * make-x.bat: Use parameter "/copy" rather than "copy" for increased
+ dwimishness for old-time DOS users. From Frank Schmitt
+ <ich@Frank-Schmitt.net>.
+
+2001-11-15 Simon Josefsson <jas@extundo.com>
+
+ * etc/gnus/unimportant.xpm, etc/gnus/important.xpm: New files.
+
+2001-11-11 Simon Josefsson <jas@extundo.com>
+
+ * make-x.bat: Don't use -nw. Suggested by Frank Haun
+ <pille3000@gmx.net>.
+
+2001-11-01 07:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * etc/smilies/blink.xpm: New set of xpm. From Oliver Scholz
+ <oscholz@my.gnus.org>.
+
+2001-10-29 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * etc/smilies/sad.pbm: New bitmap.
+ * etc/smilies/blink.pbm: Ditto.
+ Contributed by Kim F. Storm <storm@cua.dk>.
+
+2001-10-19 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+ From Frank Schmitt <ich@Frank-Schmitt.net>.
+
+ * make-x.bat: Use correct directory structure for XEmacs on Windows.
+
+2001-10-06 08:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * Makefile.in (uninstall): Add.
+
+ * etc/Makefile.in (uninstall): Add.
+
+2001-09-27 14:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * aclocal.m4 (GNUS_CHECK_FONTS): Typo. Use /dev/null as latex input.
+
+2001-09-27 09:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * aclocal.m4, configure.in: Check commercial fonts.
+
+2001-09-24 19:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * configure.in: Generate texi/ps/Makefile.
+
+2001-09-21 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * make.bat: Use parameter "/copy" rather than "copy" for increased
+ dwimishness for old-time DOS users.
+
+2001-09-18 22:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * make-x.bat: New.
+
+2001-07-04 Yair Friedman <yairfr@Amdocs.com>
+
+ * make.bat: Use infohack.el to create info files.
+
+2001-05-17 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * etc/Makefile.in (datadir): Set this variable, like in the other
+ Makefile.in's. Patch from Gaute B Strokkenes <gs234@cam.ac.uk>.
+
2001-02-11 18:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
* GNUS-NEWS: Copyright and others.
\f
* Changes in Oort Gnus
-** gnus-group-charset-alist and gnus-group-ignored-charsets-alist
+** Message supports the Importance: header.
+
+In the message buffer, C-c C-p cycles through the valid values.
+
+** Gnus supports Cancel Locks in News.
+
+This means a header "Cancel-Lock" is inserted in news posting. It is
+used to determine if you wrote a article or not (for
+cancelling/superseding). The behaviour can be changed by customizing
+`message-insert-canlock'.
+
+** Gnus supports server-side mail filtering using Sieve.
+
+Sieve rules can be added as Group Parameters for groups, and the
+complete Sieve script is generated using `D g' from the Group buffer,
+and then uploaded to the server using `C-c C-l' in the generated Sieve
+buffer. Search the online Gnus manual for "sieve", and see the new
+Sieve manual, for more information.
+
+** Extended format specs.
+
+Format spec "%&user-date;" is added into
+gnus-summary-line-format-alist. Also, user defined extended format
+specs are supported. The extended format specs look like "%u&foo;",
+which invokes function gnus-user-format-function-foo. Because "&" is
+used as the escape character, old user defined format "%u&" is no
+longer supported.
+
+** `/ *' (gnus-summary-limit-include-cached) is rewritten.
+
+It was aliased to `Y c' (gnus-summary-insert-cached-articles). The new
+function filters out other articles.
+
+** Group names are treated as UTF-8 by default.
+
+This is supposedly what USEFOR wants to migrate to. See
+`gnus-group-name-charset-group-alist' and
+`gnus-group-name-charset-method-alist' for customization.
+
+** The nnml and nnfolder backends store marks for each groups.
+
+This makes it possible to take backup of nnml/nnfolder servers/groups
+separately of .newsrc.eld, while preserving marks. It also makes it
+possible to share articles and marks between users (without sharing
+the .newsrc.eld file) within e.g. a department. It works by storing
+the marks stored in .newsrc.eld in a per-group file ".marks" (for
+nnml) and "groupname.mrk" (for nnfolder, named "groupname"). If the
+nnml/nnfolder is moved to another machine, Gnus will automatically use
+the .marks or .mrk file instead of the information in .newsrc.eld.
+The new server variables `nnml-marks-is-evil' and
+`nnfolder-marks-is-evil' can be used to disable this feature.
+
+** The menu bar (in Group and Summary buffer) named "Misc" has been
+renamed to "Gnus".
+
+** The menu bar (in Message mode) named "MML" has been renamed to
+"Attachments".
+
+** gnus-group-charset-alist and gnus-group-ignored-charsets-alist.
The regexps in these variables are compared with full group names
instead of real group names in 5.8. Users who customize these
("^han\\>" euc-kr) -> ("\\(^\\|:\\)han\\>" euc-kr)
-** Gnus now supports PGP-MIME (RFC2015) and SMIME.
+** Gnus supports PGP (RFC 1991/2440), PGP-MIME (RFC 2015/3156) and
+SMIME.
** Gnus inlines external parts (message/external).
cd texi && $(MAKE) EMACS="$(EMACS)" install
cd etc && $(MAKE) EMACS="$(EMACS)" install
+uninstall:
+ cd lisp && $(MAKE) lispdir="$(lispdir)" uninstall
+ cd texi && $(MAKE) uninstall
+ cd etc && $(MAKE) uninstall
+
# Rule for Lars and nobody else.
some:
cd lisp && $(MAKE) EMACS="$(EMACS)" some
distclean:
make clean
rm -rf *~
- for i in lisp texi etc; do (cd $$i; make distclean); done
+ for i in lisp texi etc texi/ps; do (cd $$i; make distclean); done
rm -f config.log config.status config.cache Makefile
config.status: $(srcdir)/configure
# If you have an Emacs named "t", then use the full path.
test "$EMACS" = t && EMACS=
test "$EMACS" || AC_PATH_PROGS(EMACS, emacs xemacs, no)
- if test $EMACS != "no"; then
+ if test "$EMACS" != "no"; then
AC_MSG_CHECKING([where .elc files should go])
dnl Set default value
lispdir="\$(datadir)/emacs/site-lisp"
AC_SUBST(URL)
AC_MSG_RESULT("${URL}")
])
+
+dnl
+dnl Perform checking available fonts: Adobe Bembo, Adobe Futura and
+dnl Bitstream Courier.
+dnl
+
+AC_DEFUN(GNUS_CHECK_FONTS, [
+test "$LATEX" = t && LATEX=
+test "$LATEX" || AC_PATH_PROGS(LATEX, latex, no)
+AC_MSG_CHECKING(for available fonts)
+AC_ARG_WITH(fonts,[ --with-fonts Assume all fonts required are available],[USE_FONTS="$withval"])
+WITH_FONTS_bembo='%'
+WITHOUT_FONTS_bembo=
+WITH_FONTS_pfu='%'
+WITHOUT_FONTS_pfu=
+WITH_FONTS_bcr='%'
+WITHOUT_FONTS_bcr=
+if test -z "${USE_FONTS}"; then
+ if test "${LATEX}" = no; then
+ :
+ else
+ OUTPUT=./conftest-$$
+ echo '\nonstopmode\documentclass{article}\usepackage{bembo}\begin{document}\end{document}' > ${OUTPUT}
+ if ${LATEX} ${OUTPUT} </dev/null >& AC_FD_CC 2>&1 ; then
+ if test -z "${USE_FONTS}"; then
+ USE_FONTS="Adobe Bembo"
+ else
+ USE_FONTS="${USE_FONTS}, Adobe Bembo"
+ fi
+ WITH_FONTS_bembo=
+ WITHOUT_FONTS_bembo='%'
+ fi
+ echo '\nonstopmode\documentclass{article}\begin{document}{\fontfamily{pfu}\fontsize{10pt}{10}\selectfont test}\end{document}' > ${OUTPUT}
+ if retval=`${LATEX} ${OUTPUT} </dev/null 2>& AC_FD_CC`; then
+ if echo "$retval" | grep 'Some font shapes were not available' >& AC_FD_CC 2>&1 ; then
+ :
+ else
+ if test -z "${USE_FONTS}"; then
+ USE_FONTS="Adobe Futura"
+ else
+ USE_FONTS="${USE_FONTS}, Adobe Futura"
+ fi
+ WITH_FONTS_pfu=
+ WITHOUT_FONTS_pfu='%'
+ fi
+ fi
+ echo '\nonstopmode\documentclass{article}\begin{document}{\fontfamily{bcr}\fontsize{10pt}{10}\selectfont test}\end{document}' > ${OUTPUT}
+ if retval=`${LATEX} ${OUTPUT} </dev/null 2>& AC_FD_CC`; then
+ if echo "$retval" | grep 'Some font shapes were not available' >& AC_FD_CC 2>&1 ; then
+ :
+ else
+ if test -z "${USE_FONTS}"; then
+ USE_FONTS="Bitstream Courier"
+ else
+ USE_FONTS="${USE_FONTS}, Bitstream Courier"
+ fi
+ WITH_FONTS_bcr=
+ WITHOUT_FONTS_bcr='%'
+ fi
+ fi
+ rm -f ${OUTPUT} ${OUTPUT}.aux ${OUTPUT}.log ${OUTPUT}.dvi
+ fi
+elif test "${USE_FONTS}" = yes ; then
+ WITH_FONTS_bembo=
+ WITHOUT_FONTS_bembo='%'
+ WITH_FONTS_pfu=
+ WITHOUT_FONTS_pfu='%'
+ WITH_FONTS_bcr=
+ WITHOUT_FONTS_bcr='%'
+fi
+AC_SUBST(WITH_FONTS_bembo)
+AC_SUBST(WITHOUT_FONTS_bembo)
+AC_SUBST(WITH_FONTS_pfu)
+AC_SUBST(WITHOUT_FONTS_pfu)
+AC_SUBST(WITH_FONTS_bcr)
+AC_SUBST(WITHOUT_FONTS_bcr)
+if test -z "${USE_FONTS}" ; then
+ USE_FONTS=no
+fi
+USE_FONTS=`echo "${USE_FONTS}" | sed 's/,\([[^,]]*\)$/ and\1/'`
+AC_MSG_RESULT("${USE_FONTS}")
+if test "${USE_FONTS}" = yes ; then
+ USE_FONTS='Set in Adobe Bembo, Adobe Futura and Bitstream Courier.'
+elif test "${USE_FONTS}" = no ; then
+ USE_FONTS=''
+else
+ USE_FONTS="Set in ${USE_FONTS}."
+fi
+AC_SUBST(USE_FONTS)
+])
--with-url=DIR Specify where to find the url package"
ac_help="$ac_help
--with-w3=DIR Specify where to find the w3 package"
+ac_help="$ac_help
+ --with-fonts Assume all fonts required are available"
# Initialize some variables set by options.
# The variables have the same names as the options, with
echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
-echo "configure:538: checking whether ${MAKE-make} sets \${MAKE}" >&5
+echo "configure:540: checking whether ${MAKE-make} sets \${MAKE}" >&5
set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
# ./install, which can be erroneously created by make from ./install.sh.
echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
-echo "configure:595: checking for a BSD compatible install" >&5
+echo "configure:597: checking for a BSD compatible install" >&5
if test -z "$INSTALL"; then
if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
# Extract the first word of "makeinfo", so it can be a program name with args.
set dummy makeinfo; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:667: checking for $ac_word" >&5
+echo "configure:669: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_MAKEINFO'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
# Extract the first word of "emacs", so it can be a program name with args.
set dummy emacs; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:698: checking for $ac_word" >&5
+echo "configure:700: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_EMACS'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
echo $ac_n "checking if $EMACS is really XEmacs""... $ac_c" 1>&6
-echo "configure:729: checking if $EMACS is really XEmacs" >&5
+echo "configure:731: checking if $EMACS is really XEmacs" >&5
elisp="(if (string-match \"XEmacs\" emacs-version) \"yes\" \"no\") "
if test -z ""noecho""; then
echo $ac_n "checking for xemacsp""... $ac_c" 1>&6
-echo "configure:734: checking for xemacsp" >&5
+echo "configure:736: checking for xemacsp" >&5
fi
if eval "test \"`echo '$''{'EMACS_cv_SYS_xemacsp'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
if test "$prefix" = "NONE"; then
echo $ac_n "checking prefix for your Emacs""... $ac_c" 1>&6
-echo "configure:766: checking prefix for your Emacs" >&5
+echo "configure:768: checking prefix for your Emacs" >&5
elisp="(expand-file-name \"..\" invocation-directory)"
if test -z ""noecho""; then
echo $ac_n "checking for prefix""... $ac_c" 1>&6
-echo "configure:771: checking for prefix" >&5
+echo "configure:773: checking for prefix" >&5
fi
if eval "test \"`echo '$''{'EMACS_cv_SYS_prefix'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
fi
echo $ac_n "checking where .elc files should go""... $ac_c" 1>&6
-echo "configure:802: checking where .elc files should go" >&5
+echo "configure:804: checking where .elc files should go" >&5
if test -z "$lispdir"; then
theprefix=$prefix
if test "x$theprefix" = "xNONE"; then
fi
echo $ac_n "checking where etc files should go""... $ac_c" 1>&6
-echo "configure:828: checking where etc files should go" >&5
+echo "configure:830: checking where etc files should go" >&5
if test -z "$etcdir"; then
etcdir="\$(lispdir)/../etc"
fi
echo $ac_n "checking for acceptable URL version""... $ac_c" 1>&6
-echo "configure:837: checking for acceptable URL version" >&5
+echo "configure:839: checking for acceptable URL version" >&5
if eval "test \"`echo '$''{'EMACS_cv_ACCEPTABLE_URL'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
if test -z ""noecho""; then
echo $ac_n "checking for url-retrieve in url""... $ac_c" 1>&6
-echo "configure:845: checking for url-retrieve in url" >&5
+echo "configure:847: checking for url-retrieve in url" >&5
fi
library=`echo url | tr _ -`
elisp="(progn (fmakunbound 'url-retrieve) (condition-case nil (progn (require '$library) (fboundp 'url-retrieve)) (error (prog1 nil (message \"$library not found\")))))"
if test -z ""noecho""; then
echo $ac_n "checking for url""... $ac_c" 1>&6
-echo "configure:852: checking for url" >&5
+echo "configure:854: checking for url" >&5
fi
if eval "test \"`echo '$''{'EMACS_cv_SYS_url'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
elisp="(file-name-directory (locate-library \"url\"))"
if test -z ""noecho""; then
echo $ac_n "checking for url_dir""... $ac_c" 1>&6
-echo "configure:896: checking for url_dir" >&5
+echo "configure:898: checking for url_dir" >&5
fi
if eval "test \"`echo '$''{'EMACS_cv_SYS_url_dir'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
echo $ac_n "checking for acceptable W3 version""... $ac_c" 1>&6
-echo "configure:934: checking for acceptable W3 version" >&5
+echo "configure:936: checking for acceptable W3 version" >&5
if eval "test \"`echo '$''{'EMACS_cv_ACCEPTABLE_W3'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
if test -z ""noecho""; then
echo $ac_n "checking for w3-form-encode-xwfu in w3_forms""... $ac_c" 1>&6
-echo "configure:942: checking for w3-form-encode-xwfu in w3_forms" >&5
+echo "configure:944: checking for w3-form-encode-xwfu in w3_forms" >&5
fi
library=`echo w3_forms | tr _ -`
elisp="(progn (fmakunbound 'w3-form-encode-xwfu) (condition-case nil (progn (require '$library) (fboundp 'w3-form-encode-xwfu)) (error (prog1 nil (message \"$library not found\")))))"
if test -z ""noecho""; then
echo $ac_n "checking for w3_forms""... $ac_c" 1>&6
-echo "configure:949: checking for w3_forms" >&5
+echo "configure:951: checking for w3_forms" >&5
fi
if eval "test \"`echo '$''{'EMACS_cv_SYS_w3_forms'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
elisp="(file-name-directory (locate-library \"w3-forms\"))"
if test -z ""noecho""; then
echo $ac_n "checking for w3_dir""... $ac_c" 1>&6
-echo "configure:993: checking for w3_dir" >&5
+echo "configure:995: checking for w3_dir" >&5
fi
if eval "test \"`echo '$''{'EMACS_cv_SYS_w3_dir'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
echo "$ac_t"""${W3}"" 1>&6
+test "$LATEX" = t && LATEX=
+test "$LATEX" || for ac_prog in latex
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1038: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_LATEX'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$LATEX" in
+ /*)
+ ac_cv_path_LATEX="$LATEX" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_LATEX="$LATEX" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_LATEX="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac
+fi
+LATEX="$ac_cv_path_LATEX"
+if test -n "$LATEX"; then
+ echo "$ac_t""$LATEX" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+test -n "$LATEX" && break
+done
+test -n "$LATEX" || LATEX="no"
+
+echo $ac_n "checking for available fonts""... $ac_c" 1>&6
+echo "configure:1075: checking for available fonts" >&5
+# Check whether --with-fonts or --without-fonts was given.
+if test "${with_fonts+set}" = set; then
+ withval="$with_fonts"
+ USE_FONTS="$withval"
+fi
+
+WITH_FONTS_bembo='%'
+WITHOUT_FONTS_bembo=
+WITH_FONTS_pfu='%'
+WITHOUT_FONTS_pfu=
+WITH_FONTS_bcr='%'
+WITHOUT_FONTS_bcr=
+if test -z "${USE_FONTS}"; then
+ if test "${LATEX}" = no; then
+ :
+ else
+ OUTPUT=./conftest-$$
+ echo '\nonstopmode\documentclass{article}\usepackage{bembo}\begin{document}\end{document}' > ${OUTPUT}
+ if ${LATEX} ${OUTPUT} </dev/null >& 5 2>&1 ; then
+ if test -z "${USE_FONTS}"; then
+ USE_FONTS="Adobe Bembo"
+ else
+ USE_FONTS="${USE_FONTS}, Adobe Bembo"
+ fi
+ WITH_FONTS_bembo=
+ WITHOUT_FONTS_bembo='%'
+ fi
+ echo '\nonstopmode\documentclass{article}\begin{document}{\fontfamily{pfu}\fontsize{10pt}{10}\selectfont test}\end{document}' > ${OUTPUT}
+ if retval=`${LATEX} ${OUTPUT} </dev/null 2>& 5`; then
+ if echo "$retval" | grep 'Some font shapes were not available' >& 5 2>&1 ; then
+ :
+ else
+ if test -z "${USE_FONTS}"; then
+ USE_FONTS="Adobe Futura"
+ else
+ USE_FONTS="${USE_FONTS}, Adobe Futura"
+ fi
+ WITH_FONTS_pfu=
+ WITHOUT_FONTS_pfu='%'
+ fi
+ fi
+ echo '\nonstopmode\documentclass{article}\begin{document}{\fontfamily{bcr}\fontsize{10pt}{10}\selectfont test}\end{document}' > ${OUTPUT}
+ if retval=`${LATEX} ${OUTPUT} </dev/null 2>& 5`; then
+ if echo "$retval" | grep 'Some font shapes were not available' >& 5 2>&1 ; then
+ :
+ else
+ if test -z "${USE_FONTS}"; then
+ USE_FONTS="Bitstream Courier"
+ else
+ USE_FONTS="${USE_FONTS}, Bitstream Courier"
+ fi
+ WITH_FONTS_bcr=
+ WITHOUT_FONTS_bcr='%'
+ fi
+ fi
+ rm -f ${OUTPUT} ${OUTPUT}.aux ${OUTPUT}.log ${OUTPUT}.dvi
+ fi
+elif test "${USE_FONTS}" = yes ; then
+ WITH_FONTS_bembo=
+ WITHOUT_FONTS_bembo='%'
+ WITH_FONTS_pfu=
+ WITHOUT_FONTS_pfu='%'
+ WITH_FONTS_bcr=
+ WITHOUT_FONTS_bcr='%'
+fi
+
+
+
+
+
+
+if test -z "${USE_FONTS}" ; then
+ USE_FONTS=no
+fi
+USE_FONTS=`echo "${USE_FONTS}" | sed 's/,\([^,]*\)$/ and\1/'`
+echo "$ac_t"""${USE_FONTS}"" 1>&6
+if test "${USE_FONTS}" = yes ; then
+ USE_FONTS='Set in Adobe Bembo, Adobe Futura and Bitstream Courier.'
+elif test "${USE_FONTS}" = no ; then
+ USE_FONTS=''
+else
+ USE_FONTS="Set in ${USE_FONTS}."
+fi
+
+
+
trap '' 1 2 15
cat > confcache <<\EOF
# This file is a shell script that caches the results of configure
ac_given_srcdir=$srcdir
ac_given_INSTALL="$INSTALL"
-trap 'rm -fr `echo "Makefile lisp/Makefile texi/Makefile etc/Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+trap 'rm -fr `echo "Makefile etc/Makefile lisp/Makefile texi/Makefile texi/gnusconfig.tex texi/ps/Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
EOF
cat >> $CONFIG_STATUS <<EOF
s%@URL@%$URL%g
s%@HAVE_w3_forms@%$HAVE_w3_forms%g
s%@W3@%$W3%g
+s%@LATEX@%$LATEX%g
+s%@WITH_FONTS_bembo@%$WITH_FONTS_bembo%g
+s%@WITHOUT_FONTS_bembo@%$WITHOUT_FONTS_bembo%g
+s%@WITH_FONTS_pfu@%$WITH_FONTS_pfu%g
+s%@WITHOUT_FONTS_pfu@%$WITHOUT_FONTS_pfu%g
+s%@WITH_FONTS_bcr@%$WITH_FONTS_bcr%g
+s%@WITHOUT_FONTS_bcr@%$WITHOUT_FONTS_bcr%g
+s%@USE_FONTS@%$USE_FONTS%g
CEOF
EOF
cat >> $CONFIG_STATUS <<EOF
-CONFIG_FILES=\${CONFIG_FILES-"Makefile lisp/Makefile texi/Makefile etc/Makefile"}
+CONFIG_FILES=\${CONFIG_FILES-"Makefile etc/Makefile lisp/Makefile texi/Makefile texi/gnusconfig.tex texi/ps/Makefile"}
EOF
cat >> $CONFIG_STATUS <<\EOF
for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
AC_PATH_ETCDIR
AC_CHECK_URL
AC_CHECK_W3
+GNUS_CHECK_FONTS
-AC_OUTPUT(Makefile lisp/Makefile texi/Makefile etc/Makefile)
+AC_OUTPUT(Makefile etc/Makefile lisp/Makefile texi/Makefile texi/gnusconfig.tex texi/ps/Makefile)
+2001-12-26 Florian Weimer <fw@deneb.enyo.de>
+
+ * gpg.el (gpg-command-default-alist): Using gpg-2comp is no longer
+ the default.
+
+2001-12-18 Josh Huber <huber@alum.wpi.edu>
+
+ * ChangeLog: changed buffer-file-coding-system back to
+ coding. (oops)
+
+2001-12-17 Josh Huber <huber@alum.wpi.edu>
+
+ * ChangeLog: changed coding to buffer-file-coding-system
+
+2001-11-22 Simon Josefsson <jas@extundo.com>
+
+ * sha1.el: Removed. (A FSF copyrighted sha1-el.el file is in
+ ../lisp/).
+
+2001-10-30 21:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * canlock.el, hex-util.el, sha1-el.el: Move to lisp.
+
+2001-10-30 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * canlock.el: (canlock-base64-encode-function): Removed.
+ (canlock-mmencode-program): Removed.
+ (canlock-mmencode-args-for-encoding): Removed.
+ (canlock-openssl-program): Renamed from `canlock-ssleay-program'.
+ (canlock-openssl-args): Renamed from `canlock-ssleay-args'.
+ (canlock-load-hook): Removed.
+ (canlock-base64-encode-string-with-mmencode): Removed.
+ (canlock-sha1-with-openssl): Renamed from
+ `canlock-sha1-with-ssleay'.
+ (canlock-hex-string-to-int): Removed.
+ (canlock-fetch-fields): Don't use `mapcar'.
+ (canlock-fetch-id-for-key): Don't use Cancel header if there is no
+ cancel command.
+ (gnus-summary-canlock-verify): Removed.
+ (wl-summary-canlock-verify): Removed.
+ (canlock-mew-summary-display): Removed.
+ (mew-summary-canlock-verify): Removed.
+ (mh-summary-canlock-verify): Removed.
+ (vm-summary-canlock-verify): Removed.
+ (cmail-summary-canlock-verify): Removed.
+ (rmail-summary-canlock-verify): Removed.
+
+2001-10-25 Simon Josefsson <jas@extundo.com>
+
+ * canlock.el (canlock-password, canlock-password-for-verify)
+ (canlock-force-insert-header): Defcustom.
+
+2001-10-17 Simon Josefsson <jas@extundo.com>
+
+ * canlock.el (sha1-binary): Autoload `sha1-binary'.
+ (canlock-sha1-function): Use it.
+ (canlock-sha1-function-for-verify): Ditto.
+
+ * sha1-el.el: New file.
+
+ * hex-util.el: Ditto.
+
+2001-08-24 16:09:14 Fabien Penso <penso@linuxfr.org>
+
+ * gpg.el (gpg-command-sign-detached): Doc fix.
+
+2001-08-07 Andreas Jaeger <aj@suse.de>
+
+ * gpg.el (gpg-passphrase-forget): Don't cache
+ gpg-passphrase-timer.
+ (gpg-passphrase-store): Check if gpg-passphrase-timer is
+ initialized already.
+
+2001-07-30 16:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ From Andreas Fuchs <asf@void.at>
+
+ * gpg.el (gpg-command-verify): --status-fd 1
+ (gpg-unabbrev-trust-alist): New.
+
2001-01-18 Colin Marquardt <colin.marquardt@usa.alcatel.com>
* gpg.el (gpg-make-temp-file): Error info.
;; Keywords: crypto
;; Created: 2000-04-28
-;; $Id: gpg-ring.el,v 1.1.1.1 2001-04-15 22:41:22 yamaoka Exp $
+;; $Id: gpg-ring.el,v 1.1.1.2 2002-01-06 22:11:27 yamaoka Exp $
;; This file is NOT (yet?) part of GNU Emacs.
\f
-;;;; Code:
+;;; Code:
(require 'gpg)
-(eval-when-compile
- (require 'cl))
+(eval-when-compile (require 'cl))
;;;; Customization:
(provide 'gpg-ring)
-;;; gpg-ring.el ends here
\ No newline at end of file
+;;; gpg-ring.el ends here
;; Keywords: crypto
;; Created: 2000-04-15
-;; $Id: gpg.el,v 1.1.1.1 2001-04-15 22:41:22 yamaoka Exp $
+;; $Id: gpg.el,v 1.1.1.2 2002-01-06 22:11:27 yamaoka Exp $
;; This file is NOT (yet?) part of GNU Emacs.
;; * Customization for all flavors of PGP is possible.
;; * The main operations (verify, decrypt, sign, encrypt, sign &
;; encrypt) are implemented.
-;; * Gero Treuner's gpg-2comp script is supported, and data which is is
-;; compatible with PGP 2.6.3 is generated.
+;; * Optionally, Gero Treuner's gpg-2comp script is supported,
+;; to generate data which is compatible with PGP 2.6.3.
;; Customizing external programs
;; =============================
;; function (bound to `C-h l' by default).
\f
-;;;; Code:
+;;; Code:
(require 'timer)
-(eval-when-compile
- (require 'cl))
+(eval-when-compile (require 'cl))
(eval-and-compile
(defalias 'gpg-point-at-eol
(defcustom gpg-command-default-alist
'((gpg . "gpg")
- (gpg-2comp . "gpg-2comp"))
+ (gpg-2comp . "gpg"))
"Default paths for some GnuPG-related programs.
Modify this variable if you have to change the paths to the
-executables required by the GnuPG interface. You can enter \"gpg\"
-for `gpg-2comp' if you don't have this script, but you'll lose PGP
-2.6.x compatibility."
+executables required by the GnuPG interface. You can enter \"gpg-2comp\"
+for `gpg-2comp' if you have obtained this script, in order to gain
+PGP 2.6.x compatibility."
:tag "GnuPG programs"
:type 'gpg-command-alist
:group 'gpg-options)
;;; Customization: Variables: GnuPG Commands:
(defcustom gpg-command-verify
- '(gpg . ("--batch" "--verbose" "--verify" signature-file message-file))
+ '(gpg . ("--status-fd" "1" "--batch" "--verbose" "--verify" signature-file message-file))
"Command to verify a detached signature.
The invoked program has to read the signed message and the signature
from the given files. It should write human-readable information to
:group 'gpg-commands)
(defcustom gpg-command-verify-cleartext
- '(gpg . ("--batch" "--verbose" "--verify" message-file))
+ '(gpg . ("--status-fd" "1" "--batch" "--verbose" "--verify" message-file))
"Command to verify a message.
The invoked program has to read the signed message from the given
file. It should write human-readable information to standard output
'(gpg-2comp . ("--batch" "--passphrase-fd=0" "--output=-"
armor textmode "--clearsign"
sign-with-key))
- "Command to create a create a \"clearsign\" text file.
+ "Command to create a \"clearsign\" text file.
The invoked program has to read the passphrase from standard input,
followed by the message to sign. It should write the ASCII-amored
signed text message to standard output, and diagnostic messages to
'(gpg-2comp . ("--batch" "--passphrase-fd=0" "--output=-"
armor textmode "--detach-sign"
sign-with-key))
- "Command to create a create a detached signature.
+ "Command to create a detached signature.
The invoked program has to read the passphrase from standard input,
followed by the message to sign. It should write the ASCII-amored
detached signature to standard output, and diagnostic messages to
;; temporary file resides in a world-writable directory.
(unless (or (memq system-type '(windows-nt cygwin32 win32 w32 mswindows))
(eq (file-modes gpg-temp-directory) 448)) ; mode 0700
- (error "Directory for temporary files (%s) must have mode 0700." gpg-temp-directory))
+ (error "Directory for temporary files (%s) must have mode 0700" gpg-temp-directory))
(setq name (make-temp-name name))
(let ((mode (default-file-modes)))
(unwind-protect
(save-window-excursion
(display-buffer (current-buffer))
(unless (y-or-n-p "Continue? ")
- (error "GnuPG operation aborted."))))))
+ (error "GnuPG operation aborted"))))))
(defmacro gpg-show-result (always-show &rest body)
"Show GnuPG result to user for confirmation.
"Forget stored passphrase."
(interactive)
(cancel-timer gpg-passphrase-timer)
+ (setq gpg-passphrase-timer nil)
(gpg-passphrase-clear-string gpg-passphrase)
(setq gpg-passphrase nil))
"Store PASSPHRASE in cache.
Updates the timeout for clearing the cache to `gpg-passphrase-timeout'."
(unless (equal gpg-passphrase-timeout 0)
+ (if (null gpg-passphrase-timer)
+ (setq gpg-passphrase-timer (timer-create)))
(timer-set-time gpg-passphrase-timer
(timer-relative-time (current-time)
gpg-passphrase-timeout))
(?u . trust-ultimate))
"Alist mapping GnuPG trust value short forms to long symbols.")
+(defconst gpg-unabbrev-trust-alist
+ '(("TRUST_UNDEFINED" . trust-undefined)
+ ("TRUST_NEVER" . trust-none)
+ ("TRUST_MARGINAL" . trust-marginal)
+ ("TRUST_FULLY" . trust-full)
+ ("TRUST_ULTIMATE" . trust-ultimate))
+ "Alist mapping capitalized GnuPG trust values to long symbols.")
+
(defmacro gpg-key-list-keys-in-buffer-store ()
'(when primary-user-id
(sort user-id 'string-lessp)
;; These notices must be retained in any copies of any part of this
;; documentation and/or software.
-;;; Code: ---------------------------------------------------------------------
+;;; Code:
(defvar md5-program "md5sum"
"*Program that reads a message on its standard input and writes an
(provide 'md5)
-;;; md5.el ends here ----------------------------------------------------------
+;;; md5.el ends here
-;;; ssl.el,v --- ssl functions for emacsen without them builtin
+;;; ssl.el --- ssl functions for emacsen without them builtin
;; Author: $Author: yamaoka $
-;; Created: $Date: 2001-04-15 22:41:22 $
-;; Version: $Revision: 1.1.1.1 $
+;; Created: $Date: 2002-01-06 22:11:27 $
+;; Version: $Revision: 1.1.1.2 $
;; Keywords: comm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Boston, MA 02111-1307, USA.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(require 'cl)
+(eval-when-compile (require 'cl))
(require 'base64)
(eval-and-compile
;; Keywords: extensions
;; Created: 1997-09-27
-;; $Id: vcard.el,v 1.1.1.2 2001-04-15 22:41:22 yamaoka Exp $
+;; $Id: vcard.el,v 1.1.1.3 2002-01-06 22:11:27 yamaoka Exp $
;; 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
(provide 'vcard)
-;;; vcard.el ends here.
+;;; vcard.el ends here
-;; @(#) xml.el --- XML parser
+;;; xml.el --- XML parser
-;; Copyright (C) 2000 Free Software Foundation, Inc.
+;; Copyright (C) 2000, 2001 Free Software Foundation, Inc.
;; Author: Emmanuel Briot <briot@gnat.com>
;; Maintainer: Emmanuel Briot <briot@gnat.com>
;; This was an invalid start tag
(error "XML: Invalid attribute list")
))))
+ (t ;; This is not a tag.
+ (error "XML: Invalid character."))
))
(defun xml-parse-attlist (end)
+Makefile
gnus
message
smilies
+datadir = @datadir@
infodir = @infodir@
prefix = @prefix@
srcdir = @srcdir@
$(INSTALL_DATA) $$p $(etcdir)/$$p; \
done
+uninstall:
+ rm -f $(etcdir)/gnus-tut.txt
+ cd $(srcdir) \
+ && for p in gnus/*.xpm gnus/*.pbm gnus/*.xbm gnus/x-splash; do \
+ rm -f "$(etcdir)/$$p"; \
+ done
+ rmdir $(etcdir)/gnus 2> /dev/null || true
+ cd $(srcdir) \
+ && for p in smilies/*.pbm; do \
+ rm -f "$(etcdir)/$$p"; \
+ done
+ rmdir $(etcdir)/smilies 2> /dev/null || true
+
Makefile: $(srcdir)/Makefile.in ../config.status
cd .. \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+2002-01-01 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus-delay.el (gnus-delay-send-queue): Renamed.
+
+ * gnus-art.el (gnus-ignored-headers): More headers,
+
+ * ietf-drums.el (ietf-drums-parse-addresses): Use `error' instead
+ of `scan-error', since XEmacs doesn't seem to support that.
+
+2001-12-31 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus-sum.el (gnus-summary-best-unread-article): Take a prefix
+ arg.
+ (gnus-summary-best-unread-subject): Ditto.
+ (gnus-summary-best-unread-subject): No, don't.
+ (gnus-summary-better-unread-subject): New command.
+
+ * gnus-xmas.el (gnus-xmas-put-image): Insert the string itself.
+
+ * lpath.el ((featurep 'xemacs)): fbind url function.
+
+ * gnus-xmas.el (gnus-xmas-article-display-xface): Use data, not
+ buffer.
+ (gnus-xmas-remove-image): Implementation that does something.
+ (gnus-xmas-article-display-xface): Mark images properly.
+
+ * gnus-art.el (gnus-mime-print-part): Use mm-temp-directory.
+
+2001-12-31 Florian Weimer <fw@deneb.enyo.de>
+
+ * gnus.el (gnus): Warn if trying to run Gnus un-byte-compiled.
+
+2001-12-31 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus-group.el (gnus-group-line-format): Added %O to the default
+ value.
+
+ * gnus-util.el (gnus-text-with-property): The smallest point is
+ point-min.
+
+ * smiley-ems.el (smiley-region): Return images.
+ (gnus-smiley-display): Allow toggling.
+ (smiley-region): Use text properties, not overlays.
+
+ * gnus-xmas.el (gnus-xmas-remove-image): New function, not
+ implemented yet.
+
+ * smiley-ems.el (smiley-update-cache): Check for valid types.
+
+ * gnus-art.el (gnus-with-article-buffer): New macro.
+
+ * gnus-picon.el (gnus-picon-transform-newsgroups): Keep the
+ strings as well as the glyphs.
+ (gnus-picon-transform-address): Ditto.
+ (gnus-picon-insert-glyph): Ditto.
+ (gnus-picon-transform-newsgroups): Toggle.
+ (gnus-picon-transform-address): Toggle.
+
+ * gnus-ems.el (gnus-remove-image): New function.
+ (gnus-put-image): Take an optional string.
+
+ * gnus-util.el (gnus-text-with-property): New function.
+
+ * gnus-art.el (gnus-delete-images): New function.
+
+ * gnus-ems.el (gnus-article-display-xface): Mark and store image.
+
+ * gnus-art.el (gnus-article-wash-status-entry): Renamed.
+ (gnus-article-wash-status): Use it.
+ (gnus-signature-toggle): Clean up.
+ (gnus-add-wash-status): New function.
+ (gnus-delete-wash-status): New function.
+ (gnus-article-hide-text-type): Use them throughout.
+ (gnus-add-image): New function.
+
+ * gnus-ems.el (gnus-article-display-xface): Use new interface.
+
+ * gnus-xmas.el (gnus-xmas-article-display-xface): Use new
+ interface.
+
+ * gnus-art.el (article-display-x-face): Cleaned up.
+
+ * rfc2047.el (rfc2047-field-value): New function.
+
+ * mail-parse.el (mail-header-field-value): New alias.
+
+ * gnus-art.el (gnus-mime-print-part): Fix typos.
+
+ * smiley-ems.el (gnus-smiley-file-types): New variable.
+ (smiley-update-cache): Use it.
+ (smiley-regexp-alist): Suffix-less smiley names.
+ (smiley-regexp-alist): Added more smileys.
+
+ * gnus-sum.el (gnus-print-buffer): Made into own function.
+ (gnus-summary-print-article): Use it.
+
+ * mailcap.el (mailcap-mime-info): Actually return the bit that we
+ looked for when REQUEST is a string.
+
+ * gnus-art.el (gnus-mime-button-commands): Add printing
+ keystroke.
+ (gnus-mime-copy-part): Doc fix.
+ (gnus-mime-print-part): New command.
+
+2001-12-31 Simon Josefsson <jas@extundo.com>
+
+ * imap.el (imap-parse-fetch): Notice empty flags responses. From
+ Nic Ferrier <nferrier@tf1.tapsellferrier.co.uk>.
+
+2001-12-30 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-picon.el (gnus-treat-from-picon): Autoload.
+ (picon): Fix doc.
+
+ * gnus-win.el (gnus-window-to-buffer): gnus-picon-buffer-name no
+ longer exists. Remove those codes.
+ * gnus.el (gnus-use-picons): Ditto.
+
+2001-12-30 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus-art.el (gnus-article-treat-fold-newsgroups): Don't
+ infloop.
+
+ * gnus-sum.el (t): New `W D' map.
+
+ * gnus-art.el (gnus-treat-fold-newsgroups): New variable.
+ (gnus-article-treat-body-boundary): Clean up.
+ (gnus-body-boundary-face): Removed.
+ (gnus-article-goto-header): Moved here.
+ (gnus-article-goto-header): Allow better regexps.
+ (gnus-article-treat-fold-newsgroups): New command.
+
+ * gnus-sum.el (gnus-summary-move-article): We have to select an
+ article to give `gnus-read-move-group-name' an opportunity to
+ suggest an appropriate default.
+
+ * rfc2047.el (rfc2047-fold-line): New function.
+ (rfc2047-unfold-line): Ditto.
+ (rfc2047-fold-region): Don't fold just after the header name.
+
+ * mail-parse.el (mail-header-fold-line): New alias.
+ (mail-header-unfold-line): Ditto.
+
+ * gnus-art.el (gnus-body-boundary-face): Renamed.
+ (gnus-article-treat-body-boundary): Use it.
+ (gnus-article-treat-body-boundary): Use an invisible header and a
+ line of underline characters.
+
+2001-12-30 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * ietf-drums.el (ietf-drums-parse-addresses): Recover from errors.
+
+ * gnus-picon.el (gnus-picon-transform-address): Skip bad addresses.
+ (gnus-picon-split-address): New function.
+ (gnus-picon-find-face): Use it.
+ (gnus-picon-transform-address): Use it. Set first to t for each
+ address.
+
+ * gnus-art.el (gnus-with-article-headers): Move to here. Define
+ the macro then use it.
+ (gnus-treatment-function-alist): Treat picons earlier.
+
+2001-12-30 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus-art.el (gnus-body-separator-face): New variable.
+ (gnus-article-treat-body-boundary): Use a blank, colored line.
+
+ * gnus-picon.el (gnus-picon-find-face): Look into misc/MISC as
+ well.
+
+ * gnus-art.el (gnus-treat-body-boundary): New variable.
+ (gnus-article-treat-unfold-headers): Use helper macro.
+ (gnus-article-treat-body-boundary): New command.
+
+ * gnus.el (gnus-logo-color-style): Change the default color.
+ (gnus-splash-face): Gray, gray.
+
+ * gnus-xmas.el (gnus-xmas-group-startup-message): Use general
+ colors.
+
+ * gnus.el (gnus-logo-color-alist): Moved here and renamed.
+ (gnus-logo-color-style): Ditto.
+ (gnus-logo-colors): Ditto.
+
+ * gnus-picon.el (gnus-picon-create-glyph): Cache glyphs.
+
+ * gnus-art.el (gnus-treat-newsgroups-picon): New variable.
+
+ * gnus-picon.el (gnus-treat-newsgroups-picon): New function.
+ (gnus-picon-transform-newsgroups): New function.
+
+ * ietf-drums.el (ietf-drums-parse-addresses): Accept a nil
+ string.
+
+ * gnus-picon.el (gnus-treat-mail-picon): Renamed.
+
+ * gnus-art.el (gnus-treat-cc-picon): New variable.
+ (gnus-treat-mail-picon): Renamed.
+
+ * gnus-picon.el: New implementation.
+ (gnus-picon-find-face): Renamed.
+ (gnus-treat-from-picon): Use it.
+ (gnus-picon-transform-address): Renamed.
+ (gnus-treat-from-picon): Use it.
+ (gnus-picon-create-glyph): Renamed.
+ (gnus-picon-transform-address): Use it.
+ (gnus-treat-cc-picon): New command.
+
+ * mm-decode.el (mm-create-image-xemacs): Separated out into
+ function.
+ (mm-get-image): Use it.
+
+ * gnus-art.el (gnus-treat-display-picons): Simplify.
+ (gnus-treat-from-picon): Renamed.
+
+ * gnus-ems.el (gnus-create-image): New function.
+ (gnus-put-image): New function.
+
+ * gnus-art.el (gnus-article-treat-unfold-headers): Doc fix.
+ (gnus-with-article-headers): New macro.
+ (gnus-article-goto-header): New function.
+
+ * gnus-xmas.el (gnus-image-type-available-p): New function.
+
+ * gnus-ems.el (gnus-image-type-available-p): New function.
+
+2001-12-30 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnrss.el (nnrss-check-group): Find the correct tag, because
+ xml.el is changed.
+
+2001-12-30 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus-art.el (gnus-article-treat-unfold-headers): Only fold when
+ lines are shorter than the window width.
+ (gnus-ignored-headers): More headers.
+
+2001-12-29 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus-art.el (gnus-treat-unfold-lines): New variable.
+ (gnus-treat-unfold-headers): Remamed.
+ (gnus-article-treat-unfold-headers): New command and keystroke.
+
+ * rfc2047.el (rfc2047-encode-message-header): Clean up.
+
+ * gnus-int.el (gnus-open-server): Mark quit-ed server as denied.
+
+2001-12-29 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * sha1-el.el (sha1-use-external): New variable.
+ (sha1-region): Use it.
+ (sha1-string): Ditto.
+
+ * dgnushack.el (dgnushack-compile): Compile gnus-picon for Emacs.
+ * gnus-picon.el: Less warnings when compile.
+
+2001-12-29 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus-picon.el (gnus-picons-news-directories): Removed obsolete
+ alias.
+ (gnus-picons-database): Default to list.
+ (gnus-picons-lookup-internal): Use it.
+
+ * nnmail.el (nnmail-article-group): Default nnmail-split-methods
+ to "bogus".
+
+ * gnus-win.el (gnus-configure-windows-hook): New hook.
+
+2001-12-29 Sascha L\e,A|\e(Bdecke <sascha@meta-x.de>
+
+ * gnus-win.el (gnus-configure-windows): Minimize tree buffer.
+
+2001-12-29 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus-sum.el (gnus-update-marks): Don't uncompress the seen
+ lists.
+ (gnus-select-newsgroup): Don't append; push.
+ (gnus-adjust-marked-articles): Remove obsolete ranges from
+ `seen'.
+ (gnus-update-marks): Clean up.
+ (gnus-select-newsgroup): Don't stomp gnus-newsgroup-seen.
+
+2001-12-29 Frank Schmitt <usereplyto@Frank-Schmitt.net>
+
+ * gnus-sum.el (gnus-summary-limit-to-age): Allow negative days.
+
+2001-12-29 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus-sum.el (gnus-auto-select-subject): New variable.
+ (gnus-summary-best-unread-subject): New function.
+ (gnus-summary-best-unread-article): Use it.
+ (gnus-summary-first-unseen-subject): New function and command.
+
+ * gnus-art.el (gnus-treatment-function-alist): Emphasize after
+ other treatments.
+
+ * gnus-util.el (gnus-put-overlay-excluding-newlines): New
+ function.
+
+ * gnus-art.el (gnus-article-show-hidden-text): Remove the type
+ from the list of hidden types.
+
+ * mm-view.el (mm-inline-text): Ditto.
+ (mm-inline-text): Ditto.
+ (mm-w3-prepare-buffer): Ditto.
+
+ * gnus-art.el (article-wash-html): Inhibit more remote fetching.
+
+2001-12-29 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus-art.el (gnus-ignored-headers): Added more headers.
+
+2001-12-29 Jesper Harder <harder@ifa.au.dk>
+
+ * gnus-srvr.el (gnus-browse-foreign-server): Compute the prefix
+ once.
+
+2001-12-29 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus-srvr.el (gnus-server-browse-in-group-buffer): Doc fix.
+
+2001-12-28 Simon Josefsson <jas@extundo.com>
+
+ * gnus-srvr.el (gnus-browse-foreign-server): Fix typo. From
+ Jesper Harder <harder@ifa.au.dk>.
+
+2001-12-27 Simon Josefsson <jas@extundo.com>
+
+ * gnus-sum.el (gnus-select-newsgroup): Make
+ `gnus-newsgroup-unseen' sorted. Make `gnus-newsgroup-unseen'
+ contain all articles (instead of none) when no seen marks have
+ been set for the group.
+ (gnus-update-marks): Use `gnus-range-add' on a uncompressed list
+ instead, it seems to result in shorter ranges.
+
+2001-12-26 11:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-util.el (mm-iso-8859-x-to-15-region): Use
+ insert-before-markers.
+ From Jesper Harder <harder@ifa.au.dk>
+
+2001-12-26 Paul Jarc <prj@po.cwru.edu>
+
+ * nnmaildir.el (nnmaildir-save-mail): create the destination
+ groups if they do not exist.
+
+2001-12-26 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * canlock.el (canlock-sha1-with-openssl): Remove unused variable.
+
+2001-12-22 22:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-group.el (gnus-group-read-ephemeral-group): Call
+ gnus-group-real-name.
+
+ * gnus-sum.el (gnus-decode-encoded-word-methods): Backslash paren.
+ (gnus-newsgroup-variables): Ditto.
+
+ * gnus.el (gnus-group-prefixed-name): If group name is prefixed,
+ return it.
+
+2001-12-21 Paul Jarc <prj@po.cwru.edu>
+
+ * gnus.el (gnus-valid-select-methods): Include nnmaildir.
+ * nnmaildir.el (top-level): Add commentary.
+ (nnmaildir-version): Indicate that nnmaildir is now a standard
+ part of Gnus, not separately released.
+
+2001-12-21 08:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-art.el, gnus-picon.el, gnus-sieve.el, gnus-sum.el:
+ * gnus-xmas.el, imap.el, mailcap.el, mm-util.el, nnfolder.el:
+ * nnheader.el, nnmail.el: Nil/NIL vs. nil.
+ From Pavel Jan\e,Bm\e(Bk <Pavel@Janik.cz>
+
+2001-12-20 15:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnmaildir.el: Copyright changes. Require cl only at compile time.
+
+2001-12-20 Simon Josefsson <jas@extundo.com>
+
+ * nnimap.el (top-level): Don't require cl. Suggested by ShengHuo
+ ZHU <zsh@cs.rochester.edu>.
+ (nnimap-close-group): Don't quote KEYLIST items. Suggested by
+ Brian P Templeton <bpt@tunes.org>.
+
+2001-12-19 17:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnmaildir.el: New.
+ From Paul Jarc <prj@po.cwru.edu>.
+
+2001-12-19 16:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nndoc.el (nndoc-type-alist): Move forward to the end.
+
+2001-12-19 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * gnus.el (gnus-find-subscribed-addresses): Replace `mapc' with
+ `dolist'.
+
+2001-12-19 01:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-win.el (gnus-frames-on-display-list): New.
+ (gnus-get-buffer-window): Use it.
+
+2001-12-19 00:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnwarchive.el (nnwarchive-mail-archive-xover): Fix the regexp.
+
+2001-12-18 11:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-win.el (gnus-get-buffer-window): Use gnus-delete-if.
+
+2001-12-18 11:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ From Harald Meland <Harald.Meland@usit.uio.no>
+
+ * gnus-win.el (gnus-get-buffer-window): New function.
+ (gnus-all-windows-visible-p): Use it.
+
+ * gnus-util.el (gnus-horizontal-recenter)
+ (gnus-horizontal-recenter, gnus-horizontal-recenter)
+ (gnus-horizontal-recenter, gnus-set-window-start): Use it.
+
+ * gnus-score.el (gnus-score-insert-help): Use it.
+
+ * gnus-salt.el (gnus-tree-recenter, gnus-generate-tree)
+ (gnus-generate-tree, gnus-highlight-selected-tree)
+ (gnus-highlight-selected-tree, gnus-tree-highlight-article): Use
+ it.
+
+ * gnus-art.el (gnus-article-set-window-start)
+ (gnus-mm-display-part, gnus-request-article-this-buffer)
+ (gnus-button-next-page, gnus-button-prev-page)
+ (gnus-article-button-next-page, gnus-article-button-prev-page):
+ Use it.
+
+2001-12-18 Josh Huber <huber@alum.wpi.edu>
+
+ * ChangeLog, ChangeLog.1, nnwfm.el, smiley.el:
+ * gnus-cite.el, gnus-delay.el, gnus-spec.el, message.el:
+ * mml1991.el, nnultimate.el: Removed buffer-file-coding-system tag.
+
+2001-12-18 01:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * ChangeLog, ChangeLog.1, nnwfm.el, gnus-smiley.el:
+ * gnus-cite.el, gnus-delay.el, gnus-spec.el, message.el:
+ * mml1991.el, nnultimate.el: Add `coding'.
+
+2001-12-17 Josh Huber <huber@alum.wpi.edu>
+
+ * ChangeLog: changed coding to buffer-file-coding-system
+ * ChangeLog.1: same
+ * nnwfm.el: same
+ * gnus-smiley.el: same
+ * gnus-cite.el: moved -*- magic cookie -*- to Local Variables
+ * gnus-delay.el: same
+ * gnus-spec.el: same
+ * message.el: same
+ * mml1991.el: same
+ * nnultimate.el: same
+
+2001-12-16 Simon Josefsson <jas@extundo.com>
+ Inspired by code by Dirk Meyer <dischi@tzi.de>.
+
+ * gnus-sum.el (gnus-summary-muttprint-program): New variable.
+ (gnus-summary-save-map): Add muttprint.
+ (gnus-summary-make-menu-bar): Ditto.
+ (gnus-summary-muttprint): New function.
+
+ * gnus-art.el (gnus-summary-pipe-to-muttprint): New function.
+
+2001-12-14 11:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * uudecode.el (uudecode-decode-region-internal): Speedup by using
+ temporary list instead of buffer.
+
+ * mm-url.el (executable-find): autoload.
+
+2001-12-12 Pavel Jan\e,Bm\e(Bk <Pavel@Janik.cz>
+
+ * gnus-mlspl.el (gnus-group-split-fancy): Doc fix (add reference
+ to variable, follow doc-string conventions).
+
+2001-12-13 Josh Huber <huber@alum.wpi.edu>
+
+ * gnus-cus.el (gnus-extra-topic-parameters): added topic parameter
+ subscribe-level
+ * gnus-topic.el (gnus-subscribe-topics): use it.
+
+2001-12-13 22:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-msg.el (gnus-summary-mail-forward): Forward all marked
+ messages. (A small patch with indentation)
+ From Sean Neakums <sneakums@zork.net>.
+
+ * gnus-uu.el (gnus-uu-grab-articles): Set gnus-current-article to
+ nil after shooting down the gnus-original-article-buffer.
+
+2001-12-13 20:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * uudecode.el (uudecode-use-external): New.
+ (uudecode-decode-region): Automatically detect external program.
+
+ * binhex.el (binhex-use-external): New.
+ (binhex-decode-region-internal): New.
+ (binhex-decode-region): Automatically detect external program.
+
+ * mm-uu.el (mm-uu-decode-function):
+ (mm-uu-binhex-decode-function): Use them.
+
+2001-12-12 Simon Josefsson <jas@extundo.com>
+
+ * nnvirtual.el (nnvirtual-always-rescan)
+ (nnvirtual-component-regexp): Fix doc.
+
+ * nnoo.el (defvoo): Add doc to defvoo variables.
+
+ * nnml.el (nnml-directory, nnml-active-file)
+ (nnml-newsgroups-file, nnml-get-new-mail, nnml-nov-is-evil)
+ (nnml-marks-is-evil, nnml-filenames-are-evil)
+ (nnml-prepare-save-mail-hook, nnml-inhibit-expiry): Fix doc.
+
+ * nnmh.el (nnmh-directory, nnmh-get-new-mail)
+ (nnmh-prepare-save-mail-hook, nnmh-be-safe): Fix doc.
+ (nnmh-possibly-change-directory): Use `nnheader-report' instead of
+ `error'.
+
+ * nnmbox.el (nnmbox-mbox-file, nnmbox-active-file)
+ (nnmbox-get-new-mail, nnmbox-prepare-save-mail-hook):
+
+ * nnfolder.el (nnfolder-directory, nnfolder-active-file)
+ (nnfolder-newsgroups-file, nnfolder-get-new-mail)
+ (nnfolder-save-buffer-hook, nnfolder-inhibit-expiry)
+ (nnfolder-nov-is-evil, nnfolder-marks-is-evil): Fix doc.
+
+ * nnbabyl.el (nnbabyl-mbox-file, nnbabyl-active-file)
+ (nnbabyl-get-new-mail, nnbabyl-prepare-save-mail-hook): Fix doc.
+
+ * imap.el, nnimap.el: Fix indentation.
+
+ * gnus-sieve.el (gnus-sieve-article-add-rule): Autoload it.
+
+2001-12-12 Didier Verna <didier@xemacs.org>
+
+ * gnus-msg.el (gnus-group-news): New function.
+ * gnus-group.el (gnus-group-mode-map): bind it to `i'.
+ * gnus-group.el (gnus-group-make-menu-bar): add a menu item for it.
+ * gnus-salt.el (gnus-carpal-group-buffer-buttons): add a button
+ for it.
+ * gnus-msg.el (gnus-summary-news-other-window): New function.
+ * gnus-msg.el ((gnus-summary-send-map "S" gnus-summary-mode-map)):
+ bind it to `i'.
+ * gnus-sum.el (gnus-summary-mode-map): bind it to `i'.
+ * gnus-sum.el (gnus-summary-make-menu-bar): add a menu item for it.
+ * gnus-salt.el (gnus-carpal-summary-buffer-buttons): add a button
+ for it (called with a prefix).
+ * gnus-msg.el (gnus-configure-posting-styles): add an optional
+ group-name argument.
+ * gnus-msg.el (gnus-setup-message): use it.
+
+2001-12-12 00:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-sum.el (gnus-summary-show-article): Fix doc.
+
+2001-12-10 17:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mml.el (mime-to-mml): Remove Content-Disposition too.
+
+2001-12-09 08:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-sum.el (gnus-summary-buffer-name): Decode group name.
+ * gnus-group.el (gnus-group-name-decode): Decode unibyte
+ strings only.
+ From TSUCHIYA Masatoshi <tsuchiya@namazu.org>
+
+2001-12-08 Nevin Kapur <nevin@jhu.edu>
+
+ * nnmail.el (nnmail-fancy-expiry-targets): New variable.
+ (nnmail-fancy-expiry-target): Use it.
+ Suggestions from Simon Josefsson <jas@extundo.com>.
+
+2001-12-07 14:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-sum.el (gnus-summary-show-article): Recount lines if not exist.
+
+2001-12-07 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnwfm.el (nnwfm-create-mapping): Use gnus-url-unhex-string.
+
+ * gnus-util.el (gnus-url-unhex-string): Move here.
+
+2001-12-07 09:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnrss.el (nnrss-decode-entities-unibyte-string): Use
+ mm-url-decode-entities-nbsp.
+
+ * nnlistserv.el, nnultimate.el, nnwarchive.el, nnweb.el:
+ * webmail.el, nnwfm.el: Use mm-url.
+
+ * mm-url.el (mm-url-fetch-form): Move from nnweb.
+ (mm-url-remove-markup): Move from nnweb.
+ (mm-url-fetch-simple): Move from webmail.
+
+ * nnslashdot.el (nnslashdot-request-post): Use mm-url-fetch-form.
+
+2001-12-07 01:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-sum.el (gnus-summary-print-truncate-and-quote): New.
+ (gnus-summary-print-article): Use it.
+
+ * gnus-util.el (gnus-replace-in-string): Typo.
+
+2001-12-06 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnweb.el (nnweb-replace-in-string): Removed.
+
+ * gnus-util.el (gnus-replace-in-string): New function.
+ (gnus-mode-string-quote): Use it.
+
+ * nnrss.el (nnrss-format-string): Use gnus-replace-in-string.
+ * nnwfm.el (nnwfm-create-mapping): Ditto.
+
+2001-12-06 01:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * dgnushack.el (dgnushack-compile): nnrss.el and
+ nnslashdot.el don't depend on nnweb, url, w3.
+
+ * nnrss.el: Use mm-url.
+
+2001-12-06 00:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-url.el (mm-url-insert-file-contents): Support file:.
+
+2001-12-05 14:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-view.el: Lower case for the description line. Sync from the
+ Emacs CVS.
+
+2001-12-05 12:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-group.el (gnus-group-find-new-groups): Fix doc.
+ From: Stefan Monnier <monnier@cs.yale.edu>
+
+2001-12-05 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * mm-view.wl (mm-inline-text): Decode a charset-encoded rich text.
+
+2001-12-04 08:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-url.el: Require executable.
+ Suggested by Katsumi Yamaoka <yamaoka@jpl.org>.
+
+2001-12-03 11:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * pop3.el (pop3-munge-message-separator): Only use valid date.
+ From Michael Welsh Duggan <md5i@cs.cmu.edu>.
+
+ * Makefile.in: gnus-load.elc may not be generated.
+
+2001-12-03 09:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-url.el: New.
+ * nnslashdot.el: Use it.
+ * mm-extern.el (mm-extern-url): Use it.
+
+2001-12-01 15:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-sum.el (gnus-summary-save-article): Nix
+ gnus-display-mime-function and gnus-article-prepare-hook.
+
+ * gnus-spec.el (gnus-parse-complex-format): Properly handle %C at
+ the beginning of lines.
+ (gnus-complex-form-to-spec): Ditto.
+
+2001-12-01 08:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-make-mft): Fix the m-s-a-file regexp.
+ From Paul Jarc <prj@po.cwru.edu>.
+
+2001-11-30 21:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el: New variable message-subscribed-address-file;
+ use it in message-make-mft. From Paul Jarc <prj@po.cwru.edu>.
+
+2001-11-30 12:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-tab-body-function): Set to nil.
+ (message-tab): Use text-mode-map or global-map.
+ Suggested by Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>.
+
+2001-11-30 Simon Josefsson <jas@extundo.com>
+
+ * gnus-agent.el (gnus-agent-fetch-headers): Use gnus-range-add
+ instead of gnus-union, for speed. Suggested by Christoph Conrad
+ <christoph.conrad@gmx.de>.
+ (gnus-agent-fetch-group-1): Add verbose message.
+
+2001-11-29 12:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-agent.el (gnus-agent-write-active): Make sure sym is a cons
+ of integers.
+
+2001-11-29 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * message.el (message-newgroups-header-regexp)
+ (message-completion-alist, message-tab-body-function): Use
+ defcustom rather than defvar.
+ (message-tab): Mention `message-tab-body-function' in doc.
+ Suggested by Karl Eichwalder.
+
+2001-11-28 16:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-uu.el (gnus-uu-save-article): Use #part instead of #mml.
+
+2001-11-28 12:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnheader.el (nnheader-find-nov-line): Don't use macro
+ gnus-delete-line.
+
+ * gnus-group.el (gnus-group-name-decode): Defun instead of defsubst.
+ (gnus-group-name-charset): Ditto.
+
+ * gnus-util.el (gnus-buffer-live-p): Ditto.
+
+2001-11-28 11:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * sieve-manage.el (sieve-manage-stream-alist): Backslash before
+ open parenthesis in doc.
+ (sieve-manage-authenticator-alist): Typo in doc.
+ * imap.el (imap-authenticator-alist): Typo in doc.
+ (imap-stream-alist): Backslash.
+
+ * gnus-sum.el (gnus-summary-limit-to-author): Missing arguments.
+ Thanks to david.goldberg6@verizon.net (David S. Goldberg)
+
+2001-11-27 14:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-topic.el (gnus-topic-mode): Add LOCAL for add-hook.
+
+ * message.el (message-mode): make-local-hook is harmless in Emacs 21.
+
+ * gnus-msg.el (gnus-configure-posting-styles): use
+ make-local-hook. Add LOCAL for add-hook.
+
+2001-11-27 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * message.el (message-mode): Use `make-local-hook' unless
+ obsolete.
+ Patch by Katsumi Yamaoka <yamaoka@jpl.org>.
+
+2001-11-26 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * canlock.el: Remove sha1.el and base64.el stuff.
+
+2001-11-26 Didier Verna <didier@xemacs.org>
+
+ * nnmbox.el (nnmbox-create-mbox): create the mbox file directory
+ if needed.
+
+2001-11-21 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * message.el (message-tamago-not-in-use-p): New function.
+ (message-strip-forbidden-properties): Use it.
+
+2001-11-26 Didier Verna <didier@xemacs.org>
+
+ * gnus-start.el (gnus-check-first-time-used): only check for
+ existence of .el[d] files.
+
+2001-11-25 15:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-util.el (mm-coding-system-priorities): Add backslash in the doc.
+
+ * message.el (message-setup-1): Clean up mc-*.
+
+2001-11-25 09:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-util.el (gnus-directory-sep-char-regexp): New variable.
+ * gnus-score.el (gnus-score-find-bnews): Use it.
+
+ * gnus-sum.el (gnus-summary-limit-to-subject): An exclusion version.
+ (gnus-summary-limit-to-author): Ditto.
+ (gnus-summary-limit-to-extra): Ditto.
+ (gnus-summary-find-matching): Support not-matching argument.
+
+2001-11-25 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * message.el (message-wash-subject): Use `insert' rather than
+ `insert-string', which is deprecated.
+
+2001-11-24 Simon Josefsson <jas@extundo.com>
+
+ * mm-encode.el (mm-encode-content-transfer-encoding): Fix error
+ message. (Gnus does not "default" to using 8bit for the message,
+ it default to use 8bit encoding and the user-supplied CTE
+ value. Calling this behaviour "treating it as 8bit" is perhaps
+ better.)
+
+ * mm-bodies.el (mm-body-encoding): Intern encoding if needed
+ (compare mm-charset-to-coding-system).
+
+2001-11-23 02:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * canlock.el (canlock-sha1-with-openssl): Use unibyte
+ buffer. Correctly decode hex.
+
+2001-11-21 01:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-agent.el (gnus-category-insert-line): Convert category
+ names to strings.
+
+2001-11-20 21:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (sha1): eval-and-compile.
+
+2001-11-20 Simon Josefsson <jas@extundo.com>
+
+ * message.el (message-allow-no-recipients): New variable.
+ (message-send): Use it, customize the prompting when posting to
+ Gcc/Fcc alone. From prj@po.cwru.edu (Paul Jarc).
+
+2001-11-20 09:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-util.el (mm-coding-system-priorities): New.
+ (mm-sort-coding-systems-predicate): New.
+ (mm-find-mime-charset-region): Resort coding systems if needed.
+ Suggested by Katsumi Yamaoka <yamaoka@jpl.org>.
+
+2001-11-20 Didier Verna <didier@xemacs.org>
+
+ * gnus-group.el (gnus-group-make-help-group): new optional
+ argument to control the error behavior.
+ * gnus-start.el (gnus-check-first-time-used): use it to avoid
+ erroring.
+
+2001-11-19 Simon Josefsson <jas@extundo.com>
+
+ * message.el (message-mode-map): Use C-c C-f C-i for Importance:
+ instead of C-c C-u. Suggested by Per Abrahamsen
+ <abraham@dina.kvl.dk>.
+
+2001-11-18 08:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnfolder.el (nnfolder-read-folder): Use group instead of
+ nnfolder-current-group.
+ Suggested by Lorentey Karoly <lorentey@elte.hu>.
+
+2001-11-17 Simon Josefsson <jas@extundo.com>
+
+ * message.el (message-send): Ask user if Fcc/Gcc should be
+ performed when no other sender was specified.
+ Suggested by prj@po.cwru.edu (Paul Jarc).
+
+2001-11-17 Simon Josefsson <jas@extundo.com>
+
+ * message.el (message-mode, message-mode-map): Use C-c C-u for
+ Importance: instead of C-c C-p (used by SC).
+
+2001-11-16 Simon Josefsson <jas@extundo.com>
+
+ * message.el (message-insert-importance-high)
+ (message-insert-importance-low): Save point.
+
+ * mail-source.el (mail-source-fetch-imap): Fix BODY.PEEK return
+ value.
+
+2001-11-16 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * message.el (message-strip-special-text-properties): New option.
+ (message-strip-forbidden-properties): Obey it.
+
+2001-11-14 Sam Steingold <sds@gnu.org>
+
+ * gnus-score.el: Fixed some doc strings to properly quote symbols.
+
+2001-11-15 Simon Josefsson <jas@extundo.com>
+
+ Support "Importance:" header in Message.
+
+ * message.el (message-mode-map): Bind C-c C-p to
+ `message-insert-or-toggle-importance'
+ (message-mode-menu): Add message-insert-importance-{high,low}.
+ (message-insert-importance-high, message-insert-importance-low)
+ (message-insert-or-toggle-importance): New functions.
+ (message-tool-bar-map): Add {un,}important.
+ (message-mode): Doc fix.
+
+2001-11-15 Simon Josefsson <jas@extundo.com>
+
+ * message.el (message-tool-bar-map): Fix attach toolbar tooltip.
+
+ * mml.el (mml-menu): Fix toolbar tooltip.
+
+2001-11-15 14:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnfolder.el (nnfolder-save-marks): gnus-prin1 takes one argument.
+ * nnml.el (nnml-save-marks): Ditto.
+
+ * gnus-sum.el (gnus-newsgroup-variables): Fix doc.
+
+2001-11-15 Simon Josefsson <jas@extundo.com>
+
+ * nnml.el (nnml-save-marks):
+ * nnfolder.el (nnfolder-save-marks): Use `gnus-prin1'.
+ Suggested by Istvan Marko <mi-gnus@imarko.dhs.org>.
+
+2001-11-15 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * gnus-art.el (gnus-article-wash-status-strings): Use
+ `copy-sequence', not `copy-seq'.
+
+2001-11-15 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * gnus-art.el (gnus-article-wash-status-strings): New constant.
+ (gnus-gnus-article-wash-status-entry): New function.
+ (gnus-article-wash-status): Use it.
+
+2001-11-13 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mml1991.el: Add coding header.
+
+2001-11-12 Simon Josefsson <jas@extundo.com>
+
+ * mml1991.el (mml1991-use, mml1991-function-alist): New variables.
+ (mml1991-gpg-sign, mml1991-gpg-encrypt): Renamed, from
+ `mml1991-sign' and `mml1991-encrypt'.
+ (mml1991-encrypt, mml1991-sign): New glue functions.
+ (mml1991-mailcrypt-sign, mml1991-mailcrypt-encrypt): New functions.
+
+ * mml.el (mml-mode-map): `C-c RET o' map for PGP.
+ (mml-menu): Add PGP to menu.
+
+ * mml-sec.el (top-level): Require mml1991. Don't require smime.
+ (mml-sign-alist, mml-encrypt-alist): Add "pgp".
+ (mml-pgp-sign-buffer, mml-pgp-encrypt-buffer)
+ (mml-secure-sign-pgp, mml-secure-encrypt-pgp): New glue functions.
+
+ * mml2015.el: Mention RFC 3156.
+
+ * mml1991.el: New file. From Sascha L\e,A|\e(Bdecke <sascha@meta-x.de>.
+
+2001-11-12 13:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-start.el (gnus-auto-subscribed-groups): Use ^nnml.
+
+ * gnus-sum.el (gnus-summary-move-article): Use number-to-string.
+ From <Michael.Cook@cisco.com>
+
+2001-11-11 Simon Josefsson <jas@extundo.com>
+
+ * message.el (top-level): Autoload sha1.
+ (message-canlock-generate): Use sha1 instead of md5 (sha1 used by
+ canlock, no need to require two different hash algs). Suggested
+ by Ferenc Wagner <wferi@bolyai1.elte.hu>.
+
+2001-11-09 Simon Josefsson <jas@extundo.com>
+
+ * gnus.el (gnus-local-domain): Fix doc. From Pavel Jan\e,Bm\e(Bk
+ <Pavel@Janik.cz>.
+
+2001-11-09 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * message.el (message-point-in-header-p): New function.
+ (message-do-auto-fill): Use it.
+ (message-beginning-of-line): New function. Goes to beginning of
+ header value (i.e., end of header name), or to beginning of line
+ if already at beginning of value. Behaves like
+ `beginning-of-line' when in message body.
+ (message-mode-map): Bind it.
+
+2001-11-08 Simon Josefsson <jas@extundo.com>
+
+ * gnus-msg.el (gnus-posting-styles): Add doc.
+
+2001-11-07 Simon Josefsson <jas@extundo.com>
+
+ * gnus-sieve.el (gnus-sieve-generate): Don't invoke sieve-mode.
+
+ * sieve-mode.el (sieve-control-commands-face)
+ (sieve-control-commands-face, sieve-action-commands-face)
+ (sieve-test-commands-face, sieve-tagged-arguments-face): New
+ faces.
+ (sieve-font-lock-keywords): Use them.
+ (sieve-mode): Only set font-lock-defaults in emacs.
+
+ * gnus-art.el (gnus-default-article-saver): Add
+ gnus-summary-save-body-in-file.
+ (gnus-summary-write-to-file): Fix doc.
+
+2001-11-07 Simon Josefsson <jas@extundo.com>
+
+ * gnus-art.el (gnus-treat-highlight-signature): Add cross
+ reference to the correct chapter in the manual.
+
+ * mml.el (mml-mode): Add cross reference to Emacs MIME manual.
+ Suggested by "Golubev I. N." <gin@mo.msk.ru>.
+
+2001-11-07 06:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mml.el (mml-preview): Bind mail-header-separator.
+
+2001-11-07 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * message.el: Always require canlock.
+ (message-ignored-supersedes-headers): Include Cancel-Lock and
+ Cancel-Key.
+ (message-insert-canlock): Don't require canlock.
+ (message-cancel-news): Don't check whether canlock is available.
+ (message-supersede): Support cancel-locks.
+
+ * gnus-art.el: Don't autoload canlock.
+
+2001-11-06 18:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mail-source.el (mail-source-fetch-imap): ASYNC param.
+ From: <andre@slamdunknetworks.com>
+
+2001-11-06 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * many files: Fix copyright lines.
+
+2001-11-05 07:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mml.el (mml-generate-mime-1): Use mm-with-unibyte-current-buffer.
+ Suggested by Dave Love <fx@gnu.org>.
+
+2001-11-04 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-kill-buffer): Remove auto-save file after
+ confirm.
+
+ * message.el (message-send-mail): Call message-generate-headers
+ once. Suggested by Matt Armstrong <matt@lickey.com>.
+
+ * gnus-topic.el (gnus-topic-rename): Initial-input.
+ Suggested by Katsuhiro Hermit Endo <hermit@koka-in.org>.
+
+2001-11-03 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * message.el (message-forbidden-properties): New constant.
+ (message-strip-forbidden-properties): New function.
+ (message-mode): Activate it.
+
+2001-11-02 17:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-util.el (mm-iso-8859-15-compatible): Fix doc.
+ (mm-hack-charsets): Fix doc.
+
+2001-11-02 Simon Josefsson <jas@extundo.com>
+
+ * gnus-int.el (gnus-check-server): Message "...done" when done.
+
+ * imap.el (imap-close): Don't message (imap-send-command-wait
+ returns if the connection is dropped).
+ (imap-wait-for-tag): Nix out message only when necessary.
+
+ * gnus-sieve.el (gnus-sieve-script): Use "stop" instead of "elsif"
+ for non-crossposting.
+ (gnus-sieve-crosspost): Default to t to be consistent with other
+ parts of Gnus.
+
+2001-11-01 18:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-util.el (mm-iso-8859-15-compatible): Add inconvertible chars.
+ (mm-iso-8859-x-to-15-table): Ditto.
+ (mm-iso-8859-x-to-15-region): Ditto.
+ (mm-find-mime-charset-region): Ditto.
+
+2001-11-01 Simon Josefsson <jas@extundo.com>
+
+ * nnimap.el (nnimap-close-asynchronous): New variable.
+ (nnimap-close-group): Use it.
+ (nnimap-expunge): Don't use it.
+
+ * imap.el (imap-callbacks): New variable.
+ (imap-remassoc): Copied from `gnus-remassoc'.
+ (imap-add-callback): New function.
+ (imap-mailbox-expunge, imap-mailbox-close): Support asynchronous
+ behaviour.
+ (imap-parse-response): Call the callback.
+
+ * message.el (message-insert-canlock): New variable.
+ (message-canlock-generate, message-canlock-password)
+ (message-insert-canlock): New functions.
+ (message-send-news): Call `message-insert-canlock'.
+ (top-level): Require canlock when compiling.
+ (message-insert-canlock): Require canlock before we need it.
+
+2001-11-01 13:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-msg.el (gnus-copy-article-buffer): Copy sequence.
+
+2001-11-01 12:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * dgnushack.el (dgnushack-make-load): A workaround for
+ custom-add-loads bug in some versions of XEmacs.
+
+2001-11-01 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-util.el (mm-charset-synonym-alist): Revert (some).
+
+2001-11-01 09:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-util.el (mm-iso-8859-x-to-15-region): New function.
+ (mm-hack-charsets): New variable.
+ (mm-iso-8859-15-compatible): New variable.
+ (mm-iso-8859-x-to-15-table): New variable.
+ (mm-find-mime-charset-region): Add parameter hack-charsets.
+
+ * mm-bodies.el (mm-encode-body): Use it.
+ * mml.el (mml-parse-1): Ditto.
+
+2001-11-01 Simon Josefsson <jas@extundo.com>
+
+ * gnus-group.el (gnus-group-make-menu-bar): Add Sieve.
+
+2001-11-01 08:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-util.el (mm-charset-to-coding-system): Return nil, if charset
+ is nil.
+
+2001-11-01 07:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * smiley-ems.el (smiley-update-cache): Auto detect file type.
+
+ * message.el (message-forward-rmail-make-body): Use
+ save-window-excursion.
+ (message-encode-message-body): Search with noerror.
+ (message-setup-1): Convert compose-mail send-actions to
+ message-send-actions.
+
+2001-11-01 Simon Josefsson <jas@extundo.com>
+
+ * sieve.el: Don't require easy-mmode. Suggested by Katsumi Yamaoka
+ <yamaoka@jpl.org>.
+
+2001-10-31 20:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * sieve-manage.el (sieve-string-bytes): No complain.
+
+2001-11-01 Simon Josefsson <jas@extundo.com>
+
+ * gnus-group.el (gnus-group-mode-map): Bind "D u" to
+ `gnus-sieve-update' and "D g" to `gnus-sieve-generate'. (Functions
+ has autoload cookies, so no `require' should be necessary.)
+
+ * sieve.el, sieve-mode.el, sieve-manage.el, gnus-sieve.el: New
+ files.
+
+2001-10-31 Simon Josefsson <jas@extundo.com>
+
+ * gnus-cus.el (gnus-group-parameters): Support integer `display'
+ parameter.
+
+ * gnus-sum.el (gnus-select-newsgroup): If group parameter
+ `display' is a number (and C-u wasn't used to enter group), only
+ fetch that number of articles.
+
+2001-10-31 Matt Armstrong <matt@lickey.com>
+
+ * gnus.el (gnus-find-subscribed-addresses): Doc fix:
+ not-subscribed -> subscribed.
+
+2001-10-31 08:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ From: Josh Huber <huber@alum.wpi.edu>
+
+ * message.el (message-subscribed-address-functions): New variable.
+ (message-subscribed-addresses): New variable.
+ (message-subscribed-regexps): New variable.
+ (message-goto-mail-followup-to): New function.
+ (message-send-mail): Add Mail-Followup-To.
+ (message-make-mft): New function.
+
+ * gnus.el (gnus-find-subscribed-addresses): New.
+
+2001-10-31 07:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mail-source.el (mail-source-fetch): If debug, don't regain signals.
+ (mail-source-fetch-pop): Ditto.
+ (mail-source-check-pop): Ditto.
+
+ * gnus-start.el (gnus-read-init-file): Ditto.
+ (gnus-activate-group): Ditto.
+ (gnus-read-newsrc-el-file): Ditto.
+
+2001-10-30 23:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-get-reply-headers): Make sure there is ", ".
+
+ * mm-util.el (mm-mime-mule-charset-alist): Move down and call
+ mm-coding-system-p. Don't correct it only in XEmacs.
+ (mm-charset-to-coding-system): Use mm-coding-system-p and
+ mm-get-coding-system-list.
+ (mm-emacs-mule, mm-mule4-p): New.
+ (mm-enable-multibyte, mm-disable-multibyte,
+ mm-enable-multibyte-mule4, mm-disable-multibyte-mule4,
+ mm-with-unibyte-current-buffer,
+ mm-with-unibyte-current-buffer-mule4): Use them.
+ (mm-find-mime-charset-region): Treat iso-2022-jp.
+
+ From Dave Love <fx@gnu.org>:
+
+ * mm-util.el (mm-mime-mule-charset-alist): Make it correct by
+ construction.
+ (mm-charset-synonym-alist): Remove windows-125[02]. Make other
+ entries conditional on not having a coding system defined for
+ them.
+ (mm-mule-charset-to-mime-charset): Use
+ find-coding-systems-for-charsets if defined.
+ (mm-charset-to-coding-system): Don't use
+ mm-get-coding-system-list. Look in mm-charset-synonym-alist
+ later. Add last resort search of coding systems.
+ (mm-enable-multibyte-mule4, mm-disable-multibyte-mule4)
+ (mm-with-unibyte-current-buffer-mule4): Just treat Mule 5 like
+ Mule 4.
+ (mm-find-mime-charset-region): Re-write.
+ (mm-with-unibyte-current-buffer): Restore buffer as well as
+ multibyteness.
+
+2001-10-30 21:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * canlock.el, sha1-el.el, hex-util.el: Move from contrib
+ directory. Thanks to Katsumi Yamaoka <yamaoka@jpl.org> and Shuhei
+ KOBAYASHI <shuhei@aqua.ocn.ne.jp>.
+
+2001-10-30 20:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-art.el (article-display-x-face): Nix buffer-read-only
+ again.
+
+ * mml2015.el (mml2015-gpg-verify): Convert <LF> to <CR><LF>.
+
+2001-10-30 13:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-spec.el (gnus-parse-simple-format): Use
+ buffer-substring-no-properties.
+
+2001-10-30 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * gnus-art.el (article-verify-cancel-lock): New function.
+
+ * nnheader.el (nntp-process-response): New variable.
+ (nnheader-init-server-buffer): Make `nntp-process-response'
+ buffer-local in `nntp-server-buffer'.
+
+ * nntp.el (nntp-prepare-post-hook): New hook.
+ (nntp-wait-for): Save a server's ID in `nntp-process-response'.
+ (nntp-async-trigger): Ditto.
+ (nntp-request-post): Insert a server's ID if there's no Message-ID
+ header; run `nntp-prepare-post-hook'.
+
+2001-10-30 04:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-art.el (article-decode-group-name): Use nnmail-fetch-field
+ instead.
+
+ * message.el (message-forward-subject-author-subject): Don't use
+ message-news-p, which widens the buffer.
+ (message-forward-make-body): New function.
+ (message-forward): Use it.
+ (message-insinuate-rmail): New.
+ (message-forward-rmail-make-body): New.
+
+2001-10-30 02:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-extern.el (mm-extern): Provide it.
+
+ * mm-partial.el (mm-partial): Provide it.
+
+2001-10-28 16:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-msg.el (gnus-setup-message): Call post-command-hook.
+
+2001-10-29 Simon Josefsson <jas@extundo.com>
+
+ * mml.el (mml-preview): Bind message-this-is-news if it is
+ news. From Jesper Harder <harder@myrealbox.com>.
+
+2001-10-28 Simon Josefsson <jas@extundo.com>
+
+ * gnus-sum.el (gnus-group-make-articles-read): Inline group.
+
+2001-10-29 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * smiley-ems.el (smiley-regexp-alist): Add support for sad and
+ ironic smilies.
+
+2001-10-27 Simon Josefsson <jas@extundo.com>
+
+ * message.el (message-indent-citation): Don't add trailing
+ whitespace when citing text.
+
+ * gnus.el (gnus-group-faq-directory): Fix. From Jesper Harder
+ <harder@ifa.au.dk>.
+
+2001-10-26 14:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnweb.el (nnweb-possibly-change-server): Create nnweb-hashtb if
+ not available.
+ (nnweb-request-scan): Nix nnweb-hashtb if ephemeral.
+ (nnweb-type-definition): Add google as alias of dejanews.
+ (nnweb-google-parse-1): Forward 1 line.
+
+2001-10-26 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus-msg.el (gnus-summary-mail-forward): Doc fix: add pointer to
+ variable `message-forward-ignored-headers'.
+
+2001-10-24 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * gnus.el (gnus-expand-group-parameter): New function.
+ (gnus-expand-group-parameters): Call it.
+ (gnus-group-fast-parameter): New function.
+ (gnus-group-find-parameter): Call it.
+
+2001-10-23 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * gnus.el (gnus-news-group-p): Rewrote. Now accepts a header
+ vector (it didn't before because of a bug).
+ * gnus-msg.el (gnus-post-news): Use header vector directly, if
+ available. Before it converted it to an article number.
+
+ This makes followup to news articles with negative numbers in
+ nnvirtual groups use news instead of mail.
+
+2001-10-23 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * gnus.el (post-method): Use `native' instead of `nil'.
+
+ * gnus-msg.el (gnus-post-method): Ditto.
+
+2001-10-23 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * gnus.el (gnus-define-group-parameter): Grammar fix.
+
+2001-10-22 Simon Josefsson <jas@extundo.com>
+
+ * gnus-msg.el (gnus-extended-version): Include
+ system-configuration.
+ Suggested by Kai.Grossjohann@CS.Uni-Dortmund.DE (Kai Gro\e,A_\e(Bjohann).
+
+2001-10-22 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * gnus.el (post-method): Customization fix: `native' is not a
+ valid value.
+ * gnus-msg.el (gnus-post-method): Doc and customization fix:
+ `native' is not a valid value.
+
+2001-10-21 Simon Josefsson <jas@extundo.com>
+
+ * nnimap.el (nnimap): Defgroup
+ (nnimap-strict-function, nnimap-strict-function-match): New
+ widget, from Per Abrahamsen <abraham@dina.kvl.dk>.
+ (nnimap-split-crosspost, nnimap-split-inbox)
+ (nnimap-split-rule, nnimap-split-predicate)
+ (nnimap-split-predicate): Defcustom.
+ (nnimap-split-inbox, nnimap-expunge-search-string)
+ (nnimap-importantize-dormant): Remove "*" from doc.
+
+2001-10-20 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus-sum.el (gnus-summary-limit-to-score): Prompt for score if
+ not supplied via prefix arg. From Lisp, make arg mandatory.
+ Suggested by Frank Schmitt.
+
+2001-10-20 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * message.el (message-do-auto-fill): Avoid calling
+ 'rfc822-goto-eoh'.
+
+2001-10-20 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+ From Paul Jarc <prj@po.cwru.edu>.
+
+ * message.el (message-get-reply-headers): Restructure the logic
+ and add comments. From Paul Jarc <prj@po.cwru.edu>.
+
+2001-10-20 Simon Josefsson <jas@extundo.com>
+
+ * message.el (message-cancel-news): Support cancel-locks.
+ Suggested by Per Abrahamsson.
+
+ * nnml.el (nnml-marks-changed-p): Use `equal' when comparing
+ conses. From David Z Maze <dmaze@MIT.EDU>.
+
+ * nnfolder.el (nnfolder-marks-changed-p): Ditto.
+
+2001-10-19 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * mm-decode.el (mm-default-directory): Fix customize type.
+
+ * message.el (message-setup-fill-variables): Kludge to use
+ normal-auto-fill-function even if auto fill is already activated.
+
+2001-10-19 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * message.el (message-do-auto-fill): New version that does not
+ rely on text properties, by Simon Josefsson <jas@extundo.com>.
+ (message-setup-1): Removed the `message-field' property.
+
+ * gnus-draft.el (gnus-draft-edit-message): Removed the
+ `message-field' property.
+
+2001-10-19 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * gnus-draft.el (gnus-draft-edit-message): Change `field' to
+ `message-field'. The `field' property has a special significance in
+ Emacs 21.
+
+ * message.el (message-send, message-setup-1): Ditto.
+
+2001-10-18 Simon Josefsson <jas@extundo.com>
+
+ * gnus-sum.el (gnus-group-make-articles-read): Call g-r-set-mark
+ when undoing.
+
+2001-10-18 Simon Josefsson <jas@extundo.com>
+ From Frank Schmitt <usereplyto@Frank-Schmitt.net>
+
+ * gnus-sum.el (gnus-summary-limit-to-display-predicate): Fix typo.
+ (gnus-summary-make-menu-bar): Ditto.
+
+2001-10-17 Simon Josefsson <jas@extundo.com>
+
+ * nnimap.el (nnimap-expiry-target): Make sure it is back to the
+ server. Suggested by ShengHuo ZHU <zsh@cs.rochester.edu>.
+
+2001-10-17 17:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-sum.el (gnus-summary-line-format-alist): user-date entry.
+ * gnus-util.el (gnus-user-date): New function.
+ From Frank Schmitt <usenet@Frank-Schmitt.net>.
+
+2001-10-17 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * message.el (message-check-news-header-syntax): Special case
+ nnvirtual groups.
+
+ * gnus-sum.el (gnus-summary-respool-default-method): Changed
+ customize type to `symbol'.
+
+2001-10-17 12:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-spec.el (gnus-parse-simple-format): Support extended spec
+ %&foo;.
+ (gnus-parse-simple-format): Support user extended spec too.
+ %u&foo; invokes gnus-user-format-function-foo.
+
+2001-10-17 11:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnml.el (nnml-request-expire-articles): Make sure it is back to
+ the server.
+ * nnmbox.el (nnmbox-request-expire-articles): Ditto.
+ * nnfolder.el (nnfolder-request-expire-articles): Ditto.
+ * nnbabyl.el (nnbabyl-request-expire-articles): Ditto.
+ * nndiary.el (nndiary-request-expire-articles): Ditto.
+ (nndiary-schedule): Defsubst it before use it.
+ (nndiary-error): eval-and-compile.
+
+2001-10-17 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * gnus-msg.el (gnus-post-method): Changed two instances of
+ `active' to `current' and one `null' to `not'.
+
+2001-10-16 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+ From Katsumi Yamaoka <yamaoka@jpl.org>.
+
+ * message.el (message-setup-fill-variables): Use
+ `normal-auto-fill-function' instead of `auto-fill-function'.
+
+2001-10-16 Simon Josefsson <jas@extundo.com>
+
+ * mml2015.el (mml2015-fix-micalg): Fix for Mutt-bug.
+ (mml2015-gpg-decrypt-1): Decanonicalize decrypted MIME
+ body. (Mailcrypt seem to do this, but gpg.el doesn't.)
+
+2001-10-16 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+ Patch by Oliver Scholz <oscholz@my.gnus.org>.
+
+ * gnus-draft.el (gnus-draft-edit-message): Add text property
+ `field' with value `header' to message headers.
+ * message.el (message-setup-1): Really add text property to all of
+ the header, not just part of it.
+
+2001-09-04 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus-group.el (gnus-group-sort-by-server): Use it.
+
+ * gnus.el (gnus-method-to-full-server-name): New, bogus function.
+
+ * gnus-topic.el (gnus-topic-sort-groups-by-server): New command
+ and keystroke.
+
+2001-10-14 Simon Josefsson <jas@extundo.com>
+
+ * dig.el: Doc fix.
+
+ * smime.el: Doc fix.
+
+ * gnus-msg.el (gnus-inews-do-gcc): Port header encoded-word
+ charset magic from message.el.
+
+2001-10-12 Simon Josefsson <jas@extundo.com>
+ Suggested by david.goldberg6@verizon.net (David S. Goldberg)
+
+ * gnus-cite.el (gnus-article-toggle-cited-text): Don't remove
+ 'cite from g-a-wash-types.
+ (gnus-cite-toggle): Ditto. Add 'cite. Set modeline.
+ (gnus-article-hide-citation): Fix.
+
+ * gnus-cite.el (gnus-article-hide-citation): Add `c' mode line
+ character.
+ (gnus-article-toggle-cited-text): Toggle `c' mode line character.
+
+ * gnus-art.el (gnus-treat-hide-citation-maybe): Remove duplicate
+ definition.
+ (gnus-signature-toggle): Toggle `s' mode line character.
+
+ * gnus-art.el (article-emphasize): Set `g-a-wash-types' after
+ doing stuff that clears it.
+
+2001-10-12 Simon Josefsson <jas@extundo.com>
+
+ * gnus-cache.el (gnus-summary-limit-include-cached): Rewrite.
+ From Eric Marsden <emarsden@laas.fr>.
+
+2001-10-12 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-do-auto-fill): Use gnus-point-at-bol.
+ (autoload): Add some autoloads.
+
+2001-10-12 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+ Suggested by Oliver Scholz <epameinondas@gmx.de>.
+
+ * message.el (message-do-auto-fill): New function. Like
+ `do-auto-fill' but don't fill when in the message header.
+ (message-setup-1): Put a text property on the message header.
+ (message-setup-fill-variables): Use `message-do-auto-fill'.
+
+2001-10-10 12:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-send-mail-partially): Insert an empty line
+ first, because of the change of message-make-lines.
+
+2001-10-10 Florian Weimer <fw@deneb.enyo.de>
+
+ * mm-util.el (mm-charset-synonym-alist): If Emacs doesn't support
+ iso-8859-15, make it an alias for iso-8859-1.
+
+2001-10-10 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * message.el (message-send-news): Don't modify the value of
+ `message-syntax-checks' if it is not a list (possibly it is
+ `dont-check-for-anything-just-trust-me').
+
+2001-10-10 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * gnus-group.el (gnus-group-name-charset-group-alist): Use
+ `find-coding-system' for XEmacs to check whether the coding-system
+ `utf-8' is available.
+
+2001-10-09 13:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * dgnushack.el (dgnushack-compile): Detect mh-e and xml.
+
+2001-10-09 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * message.el (message-send-news): Oops, missed case with no
+ "Followup-To" header...
+
+2001-10-09 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * message.el (message-send-news): Allow
+ `gnus-group-name-charset-group-alist' to affect encoding of the
+ "Newsgroups" and "Followup-To" headers.
+
+2001-10-07 15:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * Makefile.in (install-el): Depend on gnus-load.el.
+
+2001-10-07 13:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * Makefile.in (install-el): Use -f.
+ From: Amos Gouaux <amos+lists.ding@utdallas.edu>
+
+2001-10-07 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * message.el (message-send-news): Don't encode Followups-To when
+ `gnus-group-name-charset-group-alist is' ".*". [Yuck]
+
+ * gnus-util.el (gnus-decode-newsgroups): No space in newsgroup
+ header.
+
+ * gnus-art.el (article-decode-group-name): Also decode
+ "Followup-To".
+
+ * rfc2047.el (rfc2047-encode-message-header): Encode without
+ asking for null methods.
+
+ * gnus-group.el (gnus-group-name-charset-group-alist): Make utf-8
+ default charset for newsgroup names in accordance with USEFOR.
+
+ * gnus-group.el (gnus-group-name-charset-method-alist,
+ gnus-group-name-charset-group-alist): Removed "*" from doc
+ strings, "*" should not be used for complex variables.
+
+2001-10-06 Simon Josefsson <jas@extundo.com>
+
+ Support UTF-8 group names better.
+
+ * message.el (message-check-news-header-syntax): Encode group
+ names before comparison.
+
+ * gnus-msg.el (gnus-copy-article-buffer): Run all
+ `gnus-article-decode-hook's except `article-decode-charset'
+ instead of hardcoding call to one of them.
+
+ * gnus-art.el (gnus-article-decode-hook): Add
+ `article-decode-group-name'.
+ (article-decode-group-name): New function, use `g-d-n'.
+
+ * gnus-group.el (gnus-group-insert-group-line): Decode
+ gnus-tmp-group using `g-d-n'.
+
+ * gnus-util.el (gnus-decode-newsgroups): New function.
+
+2001-10-06 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * gnus-srvr.el (gnus-browse-foreign-server): Fixed bug non-nil
+ `gnus-group-name-charset-group-alist'.
+
+2001-10-06 08:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * Makefile.in: Install el in install. Add uninstall.
+
+2001-10-05 Simon Josefsson <jas@extundo.com>
+
+ * nnheader.el (gnus-verbose-backends, gnus-nov-is-evil): Custom.
+
+ * gnus-sum.el (gnus-summary-move-article): Also activate new groups.
+
+ * nnfolder.el (nnfolder-normalize-buffer): Don't insert \n\n in
+ empty folders.
+
+ * gnus-sum.el (gnus-select-newsgroup): Don't enable `display'
+ limiting if read-all (C-u RET) was used.
+
+2001-10-04 Simon Josefsson <jas@extundo.com>
+
+ * mail-source.el (mail-source-movemail-program): New variable.
+ (mail-source-movemail): Use it. Suggested by Taylor Hutt
+ <thutt@thutt.vmware.com>.
+
+2001-10-03 Simon Josefsson <jas@extundo.com>
+
+ * gnus-sum.el (gnus-summary-from-or-to-or-newsgroups): New param.
+ (gnus-summary-line-format-alist): Fix param.
+
+2001-10-02 Simon Josefsson <jas@extundo.com>
+
+ * nnimap.el (nnimap-request-move-article): Use imap.el directly,
+ don't go through `nnimap-request-expire-articles' to delete the
+ article. Thanks to prj@po.cwru.edu (Paul Jarc).
+
+2001-10-02 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-agent.el (gnus-agent-write-active): The min in the
+ agent/active may be larger than that in the server/active.
+
+2001-10-01 Simon Josefsson <jas@extundo.com>
+
+ * mail-source.el (mail-source-fetch-imap): Use BODY.PEEK if server
+ is IMAP4rev1.
+
+ * nnml.el (gnus-article-unpropagatable-p): Autoload gnus-sum.
+
+ * nnfolder.el: Ditto.
+
+2001-09-30 Dan Christensen <jdc+news@uwo.ca>
+
+ * gnus-sum.el (gnus-summary-extract-address-component): New function.
+ (gnus-summary-from-or-to-or-newsgroups): Optimize.
+
+2001-09-29 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * message.el (message-mode-map): Keybinding for `gnus-delay-article'.
+ (message-mode-menu): Menu item for same.
+
+ * gnus-group.el (gnus-group-make-menu-bar): Menu item for sending
+ delayed articles.
+
+ * gnus-delay.el (gnus-delay-send-drafts): Do nothing if
+ nndraft:delayed does not exist.
+ (gnus-delay-initialize): Don't set up keymap, that's done from
+ message.el now.
+ (gnus-delay, gnus-delay-group, gnus-delay-header)
+ (gnus-delay-default-delay, gnus-delay-default-hour): Customize.
+
+2001-09-29 Simon Josefsson <jas@extundo.com>
+
+ * mm-util.el (mm-mime-mule-charset-alist): Encode mule-utf-8 as
+ utf-8, not eight-bit-control.
+
+ * imap.el (imap-shell-host, imap-default-user, imap-use-utf7)
+ (imap-log, imap-debug): Custom.
+ (imap-log-buffer, imap-debug-buffer): New constants.
+ (imap-kerberos4-open, imap-gssapi-open, imap-ssl-open)
+ (imap-network-open, imap-shell-open, imap-starttls-open)
+ (imap-send-command-1, imap-send-command, imap-arrival-filter)
+ (imap-debug): Use imap-*-buffer.
+
+ * nndoc.el (nndoc-article-type): Add mailman.
+ (nndoc-type-alist): Ditto.
+ (nndoc-mailman-type-p): New function.
+
+2001-09-28 07:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-xmas.el (gnus-article-x-face-command): Merge it into
+ gnus-art.el.
+
+2001-09-27 Simon Josefsson <jas@extundo.com>
+
+ * gnus-topic.el (gnus-topic-mode-map): Add catchup.
+ (gnus-topic-catchup-articles): New function. Suggested by Robin
+ S. Socha <robin-dated-1001857693.185e29@socha.net>.
+
+2001-09-27 11:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ From Gerd M\e,Av\e(Bllmann <gerd@gnu.org>.
+
+ * gnus-ems.el (gnus-article-display-xface): Insert xface after
+ previous ones.
+
+2001-09-27 07:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ From Daiki Ueno <ueno@unixuser.org>
+
+ * gnus-sum.el (gnus-summary-show-article): The arglist of
+ detect-coding-region is incompatible.
+
+2001-09-26 18:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ From Katsuhiro Hermit Endo <hermit@koka-in.org>
+
+ * gnus-group.el (gnus-group-delete-group): Typo.
+
+2001-09-26 Simon Josefsson <jas@extundo.com>
+
+ * nnmail.el (nnmail-expiry-target-group): Add doc warning.
+
+ * nnimap.el (nnimap-expiry-target): Use temp buffer.
+
+2001-09-26 07:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-cus.el (gnus-group-parameters): Display as sexp.
+
+2001-09-22 Simon Josefsson <jas@extundo.com>
+
+ * nnml.el (nnml-open-marks): Remove unpropagatable marks.
+
+ * nnfolder.el (nnfolder-open-marks): Ditto.
+
+ * gnus-sum.el (gnus-article-unpropagatable-p): New function.
+ (gnus-update-marks): Use it.
+ (gnus-update-marks): Use `gnus-article-mark-to-type' instead of
+ hardcoded list.
+
+ * gnus.el (gnus-article-special-mark-lists): Add killed.
+ (gnus-article-unpropagated-mark-lists): New constant.
+
+2001-09-22 Simon Josefsson <jas@extundo.com>
+
+ * gnus-sum.el (gnus-summary-mode-hook): Add gnus-pick-mode as
+ custom option.
+
+2001-09-23 Simon Josefsson <jas@extundo.com>
+
+ * gnus-draft.el (gnus-draft-setup): Add mark in backend as well.
+
+2001-09-23 02:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-msg.el (gnus-button-mailto): Hack save-selected-window-window.
+
+2001-09-22 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * gnus-group.el (gnus-group-sort-function): Fix customize type to
+ accept lists of functions.
+
+2001-09-20 Simon Josefsson <jas@extundo.com>
+
+ * gnus-group.el (gnus-group-catchup): Update expire marks in
+ backend. Also, if ALL also set expire marks on tick/dormant.
+
+2001-09-20 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * message.el (message-tab-body-function): New variable.
+ * message.el (message-tab): Use it.
+
+2001-09-19 Sam Steingold <sds@gnu.org>
+
+ * gnus-win.el (gnus-buffer-configuration): Respect
+ `gnus-bug-create-help-buffer'.
+
+2001-09-18 Simon Josefsson <jas@extundo.com>
+
+ * gnus-spec.el (gnus-correct-pad-form): Re-revert.
+ (gnus-parse-simple-format): Re-revert.
+
+2001-09-16 Katsuhiro Hermit Endo <hermit@koka-in.org>
+
+ * gnus-spec.el (gnus-parse-complex-format): Don't fold search
+ case. (Thanks to Daiki Ueno <ueno@unixuser.org>.)
+
+2001-09-18 Simon Josefsson <jas@extundo.com>
+
+ * gnus-spec.el (gnus-correct-pad-form): Remove until papers are
+ signed.
+ (gnus-parse-simple-format): Don't use it.
+
+2001-09-17 Miles Bader <miles@gnu.org>
+
+ * gnus-srvr.el (gnus-server-insert-server-line): Don't let an
+ error querying a backend abort the whole process.
+
+2001-09-17 08:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-srvr.el (gnus-server-mode): Fix bogus fontification.
+ From Gerd M\e,Av\e(Bllmann <gerd@gnu.org>.
+
+2001-09-17 Didier Verna <didier@xemacs.org>
+
+ * nndiary.el: version 0.2-b14.
+ * gnus-diary.el (gnus-diary-check-message): fix `read-string'
+ compatibility problem with XEmacs 21.1.
+
+2001-09-15 Simon Josefsson <jas@extundo.com>
+
+ * gnus-group.el (gnus-group-line-format): Document %c.
+
+ * nnml.el (nnml-parse-head): Handle CRLF files.
+ (nnml-generate-nov-file): Ditto.
+ (nnml-retrieve-headers): Ditto.
+
+2001-09-15 Michael Welsh Duggan <md5i@cs.cmu.edu>
+
+ * gnus-spec.el (gnus-parse-format): Don't treat %c as %C.
+
+2001-09-13 Martin Kretzschmar <Martin.Kretzschmar@inf.tu-dresden.de>
+
+ * gnus-spec.el (gnus-correct-substring): Still stopped one
+ character before we wanted (never included last character).
+ (gnus-tilde-max-form, gnus-tilde-cut-form) Made readable again,
+ add missing "," (once per function)
+
+2001-09-14 Simon Josefsson <jas@extundo.com>
+
+ * gnus-start.el (gnus-group-mode-hook): Moved from gnus-group
+ (otherwise e.g. gnus-agentize in .gnus overrides the customized
+ default before gnus-group is loaded and the variable set.)
+
+ * nnimap.el (nnimap-request-set-mark): Do not store bookmark,
+ killed or unsent marks.
+
+ * gnus-draft.el (gnus-draft-setup): Don't set mark when there
+ isn't an article to set it on (e.g. when you `a' in a group).
+
+2001-09-12 Pavel Jan\e,Bm\e(Bk <Pavel@Janik.cz>
+
+ * mm-util.el (mm-charset-synonym-alist): add windows-1250 so we
+ can read e-mails from Microsoft Outlook users not using ISO
+ 8859-2 character set.
+
+2001-09-12 18:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-diary.el: Minor modifications to avoid warnings.
+ (gnus-summary-misc-menu): defvar.
+ (gnus-diary-check-message): Use gnus-point-at-eol.
+ (gnus-diary-kill-entire-line): eval-and-compile.
+
+2001-09-12 Didier Verna <didier@xemacs.org>
+
+ * nndiary.el: new version (0.2-b13).
+ * nndiary.el (nndiary-mail-sources): doc update.
+ * nndiary.el (nndiary-split-methods): ditto.
+ * nndiary.el (nndiary-request-accept-article-hooks): New.
+ * nndiary.el (nndiary-request-accept-article): use it, check
+ message validity.
+ * nndiary.el (nndiary-get-new-mail): changed default to nil.
+ * nndiary.el (nndiary-schedule): fix bug (misplaced
+ condition-case): it didn't return nil on error.
+ * gnus-diary.el: new version.
+ * gnus-diary.el (gnus-diary-summary-line-format): removed %I.
+ * gnus-diary.el (gnus-diary-header-value-history): New.
+ * gnus-diary.el (gnus-diary-narrow-to-headers): New.
+ * gnus-diary.el (gnus-diary-add-header): New.
+ * gnus-diary.el (gnus-diary-check-message): New.
+ * gnus-diary.el (message-mode-map): bind the above to `C-c D c'.
+ * gnus-diary.el (gnus-article-edit-mode-map): ditto.
+
+2001-09-10 TSUCHIYA Masatoshi <tsuchiya@namazu.org>
+
+ * gnus-sum.el (gnus-select-newsgroup): Make
+ `gnus-current-select-method' buffer-local.
+
+ * gnus-art.el (gnus-request-article-this-buffer): Refer
+ `gnus-current-select-method' in the current summary buffer.
+
+2001-09-10 Simon Josefsson <jas@extundo.com>
+ From Daniel Pittman <daniel@rimspace.net>
+
+ * gnus-spec.el (gnus-correct-pad-form): Fix.
+
+2001-09-09 Simon Josefsson <jas@extundo.com>
+
+ * mm-decode.el (mm-inline-media-tests): Add
+ application/x-emacs-lisp.
+ (mm-attachment-override-types): Add
+ application/{x-,}pkcs7-signature.
+
+ * gnus-srvr.el (gnus-server-mode-hook, gnus-server-exit-hook)
+ (gnus-server-line-format, gnus-server-mode-line-format)
+ (gnus-server-browse-in-group-buffer): Customize.
+
+2001-09-08 16:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnml.el (nnml-marks-changed-p): Typo.
+ (nnml-save-marks, nnml-open-marks): Use gnus-sethash.
+ (nnml-marks-changed-p): Use gnus-gethash.
+ (nnml-marks-modtime): Use gnus-make-hashtable.
+
+ * nnfolder.el (nnfolder-marks-changed-p): Typo.
+ (nnfolder-request-expire-articles, nnfolder-save-marks)
+ (nnfolder-open-marks): Typo.
+ (nnfolder-save-marks, nnfolder-open-marks): Use gnus-sethash.
+ (nnfolder-marks-changed-p): Use gnus-gethash.
+ (nnfolder-marks-modtime): Use gnus-make-hashtable.
+
+2001-09-08 Simon Josefsson <jas@extundo.com>
+
+ * nnfolder.el (nnfolder-marks-modtime): New variable.
+ (nnfolder-marks-changed-p): New function.
+ (nnfolder-save-marks, nnfolder-open-marks): Save modtime.
+ (nnfolder-request-update-info): Don't update if marks didn't change.
+
+ * nnml.el (nnml-marks-modtime): New variable.
+ (nnml-marks-changed-p): New function.
+ (nnml-save-marks, nnml-open-marks): Save modtime.
+ (nnml-request-update-info): Don't update if marks didn't change.
+
+ * gnus-agent.el (gnus-agent-any-covered-gcc)
+ (gnus-agent-add-server, gnus-agent-remove-server): Use
+ gnus-agent-method-p.
+
+ * gnus-art.el (gnus-buttonized-mime-types): New variable.
+ (gnus-unbuttonized-mime-type-p): Use it.
+
+ * gnus-agent.el (gnus-agent-fetch-group): If online, actually
+ fetch group.
+
+2001-09-08 Simon Josefsson <jas@extundo.com>
+ From Daniel Pittman <daniel@rimspace.net>
+
+ * gnus-spec.el (gnus-correct-pad-form): New function.
+ (gnus-parse-simple-format): Use it.
+
+2001-09-07 Simon Josefsson <jas@extundo.com>
+
+ * gnus-group.el (gnus-group-sort-groups): Unmark all groups.
+ (gnus-group-sort-selected-groups): Ditto. Suggested by Harry
+ Putnam <reader@newsguy.com>.
+ (gnus-group-sort-selected-groups): Touch dribble file.
+
+2001-09-07 Raja R Harinath <harinath@cs.umn.edu>
+
+ * nnml.el (nnml-filenames-are-evil): New variable.
+ (nnml-article-to-file-alist): Rename to ...
+ (nnml-current-group-article-to-file-alist): ... this.
+ Respect `nnml-filenames-are-evil'.
+ (nnml-active-number): Update.
+ (nnml-update-file-alist): Update.
+ (nnml-request-article): Use nnheader-article-to-file-alist.
+ (nnml-request-rename-group): Likewise.
+
+2001-09-06 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * gnus-sum.el (gnus-summary-insert-line): Fix.
+
+2001-09-06 Bj\e,Av\e(Brn Torkelsson <torkel@acc.umu.se>
+
+ * gnus-sum.el: Bind g-s-t-s to "W g".
+ * gnus-sum.el (gnus-summary-make-menu-bar): Add g-s-t-s.
+ * gnus-sum.el (gnus-summary-toggle-smiley): New function. Toggles
+ display of graphical smilies.
+
+2001-09-07 02:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-start.el (gnus-setup-news): A typo.
+ From Bill White <billw@wolfram.com>.
+
+2001-09-06 Simon Josefsson <jas@extundo.com>
+
+ * gnus-sum.el (gnus-summary-insert-line): Insert forwarded, recent
+ and unseen marks.
+
+2001-09-05 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * nnmail.el (nnmail-split-fancy): Document `junk'.
+
+2001-09-04 Simon Josefsson <jas@extundo.com>
+
+ * imap.el (imap-search): Don't error if server is broken.
+
+2001-09-02 Benjamin Rutt <brutt@bloomington.in.us>
+
+ * nnmbox.el (nnmbox-find-article): Fix infinite loop when
+ searching for an article that isn't in the mbox.
+
+2001-09-02 23:12:48 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * nnslashdot.el (nnslashdot-retrieve-headers-1): Get references
+ right, and get all the comments.
+
+2001-09-02 Simon Josefsson <jas@extundo.com>
+ Suggested by Dan Christensen <jdc+news@uwo.ca>
+
+ * nnfolder.el (nnfolder-request-update-info): Fix message.
+
+ * nnml.el (nnml-request-update-info): Ditto.
+
+2001-09-01 Simon Josefsson <jas@extundo.com>
+
+ * nnml.el (nnml-request-expire-articles): Also bind
+ `nnml-current-group' and `nnml-article-file-alist' when using
+ expiry-target. (Otherwise nnml will be in a inconsistent internal
+ state causing all kind of problems.)
+ (nnml-request-expire-articles): If `nnml-article-to-file' or
+ `file-attributes' failes, return article as un-expirable instead
+ of treating it as expired.
+
+2001-08-31 Sam Steingold <sds@gnu.org>
+
+ * imap.el (imap-mailbox-examine, imap-mailbox-examine-1): Fix a
+ typo: `exmine' --> `examine'.
+
+2001-08-30 13:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nndoc.el (nndoc-forward-type-p): It is not a digest.
+
+2001-08-30 11:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnml.el (nnml-check-directory-twice): Remove.
+ (nnml-retrieve-headers): Ditto.
+ (nnml-article-to-file): Use nnheader-directory-files-is-safe.
+
+2001-08-30 Andrew Innes <andrewi@gnu.org>
+
+ * nnheader.el (nnheader-directory-files-is-safe): No need to read
+ directory twice on Windows, or on GNU Emacs-21.
+
+2001-08-30 Andrew Innes <andrewi@gnu.org>
+
+ * nnml.el (nnml-request-article): Use nnml-article-to-file-alist.
+ (nnml-request-rename-group): Ditto.
+ (nnml-active-number): Ditto.
+ (nnml-request-create-group): Use nnml-directory-articles.
+ (nnml-request-expire-articles): Use nnml-directory-articles, which
+ gets list from nov database if available.
+ (nnml-get-nov-buffer): New function.
+ (nnml-open-nov): Use it.
+ (nnml-update-file-alist): Use nnml-article-to-file-alist, which
+ gets alist from nov database if available.
+ (nnml-directory-articles): New function.
+ (nnml-article-to-file-alist): New function.
+
+2001-08-30 Andrew Innes <andrewi@gnu.org>
+
+ * mm-decode.el (mm-display-external): Use `name' as filename, if
+ `filename' attribute is not present.
+
+2001-08-30 Andrew Innes <andrewi@gnu.org>
+
+ * mail-source.el (mail-source-flash): New defcustom.
+ (mail-source-new-mail-p): Ring visible bell if appropriate.
+ (mail-source-start-idle-timer): Use unwind-protect to ensure idle
+ timer is cleared even if mail check signals an error.
+
+2001-08-29 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-sum.el (gnus-summary-move-article): Only update marks of
+ type 'list.
+
+2001-08-29 00:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * flow-fill.el (fill-flowed): eol might be point-max.
+
+2001-08-27 Simon Josefsson <jas@extundo.com>
+
+ * nnml.el (nnml-request-update-info): Fix message.
+ (nnml-open-marks): Ditto.
+
+ * nnfolder.el (nnfolder-request-update-info):
+ (nnfolder-open-marks): Fix message.
+
+2001-08-25 Simon Josefsson <jas@extundo.com>
+
+ * nnfolder.el (nnfolder-save-marks): Don't create directory named
+ after group in ~/.
+
+2001-08-25 Simon Josefsson <jas@extundo.com>
+ From Andreas Jaeger <aj@suse.de>
+
+ * nnfolder.el (nnfolder-open-marks): Fix typo.
+ * nnml.el (nnml-open-marks): Likewise.
+
+2001-08-25 Simon Josefsson <jas@extundo.com>
+
+ Make nnfolder groups self-contained as far as marks are concerned.
+
+ * nnfolder.el (nnfolder-marks-directory, nnfolder-marks-is-evil)
+ (nnfolder-marks, nnfolder-marks-file-suffix): New variables.
+ (nnfolder-open-server): Make marks directory.
+ (nnfolder-request-delete-group): Delete marks file.
+ (nnfolder-request-delete-group): Check of nov/marks file exist
+ before deleting.
+ (nnfolder-request-rename-group): Rename marks file.
+ (nnfolder-request-rename-group): Only rename nov/mark if they exists.
+ (nnfolder-request-set-mark, nnfolder-request-update-info)
+ (nnfolder-group-marks-pathname, nnfolder-save-marks)
+ (nnfolder-open-marks): New functions.
+ (top-level): Require gnus.
+
+2001-08-25 09:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnweb.el (nnweb-type-definition): Use google raw file.
+ (nnweb-google-parse-1): Ditto.
+ (nnweb-google-identity): Ditto.
+ (nnweb-reference-wash-article): Move nnweb-decode-entities here.
+ (nnweb-altavista-wash-article): Ditto.
+ (nnweb-request-article): Remove nnweb-decode-entities.
+
+ * nnml.el: Require 'gnus.
+
+2001-08-25 Simon Josefsson <jas@extundo.com>
+
+ * nnml.el (nnml-marks-is-evil): Add doc.
+
+2001-08-25 Simon Josefsson <jas@extundo.com>
+
+ * nnml.el (nnml-save-marks): Wrap saving marks in a
+ condition-case, to allow user to start Gnus if saving marks failed
+ for some reason.
+
+2001-08-24 16:05:38 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus-spec.el (gnus-compile): Don't compile gnus-version.
+
+ * gnus-group.el (gnus-update-group-mark-positions): Bind
+ gnus-group-update-hook to nil.
+
+2001-08-24 13:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mml.el (mml-generate-mime-1): Force as multibyte string.
+
+2001-08-24 12:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-sum.el (gnus-summary-insert-line)
+ (gnus-summary-prepare-threads): gnus-tmp-lines should be a string.
+ From Martin Kretzschmar <Martin.Kretzschmar@inf.tu-dresden.de>
+
+ * gnus-spec.el (gnus-correct-substring): Take optional END.
+
+ * nnrss.el (nnrss-request-article): Remove \n.
+ (nnrss-retrieve-headers): Lines number is -1.
+
+2001-08-24 Simon Josefsson <jas@extundo.com>
+
+ * gnus-group.el (gnus-info-clear-data): Call
+ nnfoo-request-set-mark to propagate marks. Fix bug:
+ `gnus-group-update-line' doesn't update read range unless we call
+ `gnus-get-unread-articles-in-group' first.
+
+ * nnimap.el (nnimap-request-set-mark): Don't propagate seen flags
+ to server.
+
+2001-08-23 21:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-util.el (gnus-create-info-command): Return an interactive
+ function.
+
+2001-08-23 19:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ From Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * gnus-spec.el (gnus-parse-complex-format): Use equal.
+
+2001-08-23 18:43:05 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus-sum.el (gnus-select-newsgroup): Use it.
+
+ * gnus-util.el (gnus-not-ignore): New function.
+
+ * lpath.el (featurep): Don't fbind char-int.
+
+ * gnus-util.el (gnus-create-info-command): New function.
+
+ * gnus-group.el (gnus-group-edit-group): Make C-c C-i go to the
+ right node.
+
+ * gnus-sum.el (gnus-select-newsgroup): Clean up.
+ (gnus-summary-limit-children): Use 'identity instead of `all'.
+ (gnus-summary-limit-to-display-predicate): New command and
+ keystroke.
+
+2001-08-23 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnrss.el (nnrss-group-alist): Use fm-releases.rdf.
+
+ * gnus-spec.el (gnus-format-specs): Miss a right parenthesis.
+
+2001-08-23 18:43:05 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus-spec.el: Add the Gnus version.
+ (gnus-update-format-specifications): If the Gnus version changes,
+ nix out the format spec cache.
+
+ * gnus.el (gnus-continuum-version): Made into a command and
+ optionalize the VERSION.
+
+ * gnus-spec.el (gnus-parse-complex-format): Remove %C specs from
+ the start of the lines.
+
+2001-08-22 00:06:52 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus.el (gnus-visual-p): Define function before use of
+ function.
+
+2001-08-21 23:28:02 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus-sum.el (gnus-adjust-marked-articles): Use new variable.
+ (gnus-article-mark-to-type): New function.
+ (gnus-update-missing-marks): Only update marks of type 'list.
+
+ * gnus.el (gnus-article-special-mark-lists): New variable.
+
+2001-08-21 12:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-sum.el (gnus-summary-limit-children): Check 'all.
+ (gnus-select-newsgroup): Still use 'all.
+ (gnus-summary-initial-limit): Comparing with 'all.
+
+2001-08-20 16:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-start.el (gnus-activate-group): If dont-check, don't update
+ active.
+
+2001-08-20 15:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnslashdot.el (nnslashdot-retrieve-headers-1): Replace
+ nnslashdot-*-retrieve-headers.
+ (nnslashdot-request-article): Fix for slashcode 2.2.
+ (nnslashdot-make-tuple): New.
+ (nnslashdot-read-groups): Use it.
+
+2001-08-20 01:34:03 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus.el (gnus-expand-group-parameters): Don't alter the variable
+ list.
+
+ * gnus-sum.el (gnus-summary-move-article): Don't select article.
+
+2001-08-20 Simon Josefsson <jas@extundo.com>
+
+ * gnus-msg.el (gnus-inews-do-gcc): If archive server can't be
+ opened, error instead of continuing (and exploding later).
+
+2001-08-20 01:34:03 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus.el (gnus-expand-group-parameters): Return the parameter
+ list.
+
+ * gnus-sum.el (gnus-summary-show-article): Doc fix.
+ (gnus-summary-show-article): Guess at charset if required.
+
+ * gnus-spec.el (gnus-correct-substring): Stopped one character
+ before we wanted.
+
+2001-08-19 Pavel Jan\e,Bm\e(Bk <Pavel@Janik.cz>
+
+ * earcon.el (earcon-auto-play): Remove unused option.
+
+2001-08-19 16:14:41 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus-score.el (gnus-score-headers): Move the "Scoring..."
+ message down in levels, since it happens very fast.
+
+ * smiley-ems.el (smiley-update-cache): Respect the symbol version
+ of smiley-regexp-alist.
+
+ * mm-view.el (mm-inline-text): Ignore vcard errors.
+
+ * gnus-art.el (gnus-ignored-headers): Added more junk headers.
+
+ * gnus-score.el (gnus-all-score-files): Use append instead of
+ nconc.
+
+ * gnus.el (gnus-splash-face): Doc fix.
+
+ * mm-decode.el (mm-mailcap-command): Use
+ mm-path-name-rewrite-functions.
+ (mm-path-name-rewrite-functions): New variable.
+
+ * gnus-spec.el (gnus-parse-complex-format): React to ?=.
+ (gnus-complex-form-to-spec): Insert tab.
+ (gnus-spec-tab): New function.
+
+ * gnus-sum.el (gnus-select-newsgroup): Set the marks before
+ entering the group.
+
+ * gnus-spec.el (gnus-complex-form-to-spec): Insert Lisp to match
+ the positional spec.
+ (gnus-parse-complex-format): React to %C.
+
+ * gnus-ems.el (gnus-char-width): Moved here.
+
+ * gnus-sum.el (gnus-select-newsgroup): Set
+ gnus-newsgroup-articles.
+ (gnus-unseen-mark): New variable.
+ (gnus-newsgroup-unseen): Ditto.
+ (gnus-newsgroup-seen): Ditto.
+ (gnus-adjust-marked-articles): Use them.
+ (gnus-update-marks): Use them.
+ (gnus-summary-update-secondary-mark): Display.
+ (gnus-summary-prepare-threads): Display.
+
+ * gnus-msg.el (gnus-inews-group-method): Use and return the
+ method, not the server.
+
+2001-08-19 Simon Josefsson <jas@extundo.com>
+
+ * gnus-srvr.el (gnus-server-agent-face): New.
+ (gnus-server-agent-face): New.
+ (gnus-server-mode): Turn on font-lock-mode.
+
+ * gnus.el (gnus-server-visual): Add defgroup.
+
+2001-08-19 Simon Josefsson <jas@extundo.com>
+ From Joe Casadonte <jcasadonte@northbound-train.com>
+
+ * gnus-srvr.el (gnus-server-opened-face, gnus-server-closed-face,
+ gnus-server-denied-face): New.
+ (gnus-server-opened-face, gnus-server-closed-face,
+ gnus-server-denied-face): New.
+ (gnus-server-font-lock-keywords): Add.
+
+2001-08-19 Simon Josefsson <jas@extundo.com>
+
+ * nnml.el (nnml-request-set-mark): Return nil.
+ (nnml-save-marks): Use nnml-possibly-create-directory.
+ (nnml-open-marks): Only work in temp buffer when inserting/reading
+ .marks file.
+
+2001-08-18 19:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.el (gnus-expand-group-parameters): Fix.
+
+ * gnus-spec.el (gnus-char-width): New.
+ (gnus-correct-substring, gnus-correct-length): Use it.
+
+ * message.el (message-required-mail-headers): Fix doc.
+
+2001-08-18 18:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-sum.el (gnus-group-make-articles-read): gnus-request-set-mark.
+
+ * mm-decode.el (mm-save-part-to-file): Insert the handle.
+
+2001-08-18 13:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnslashdot.el (nnslashdot-threaded-retrieve-headers):
+ slashdot 2.2 (not fully fixed yet).
+ (nnslashdot-request-article): Ditto.
+
+2001-08-18 Simon Josefsson <jas@extundo.com>
+
+ * gnus-util.el (gnus-remassoc, gnus-update-alist-soft): Moved from
+ nnimap.
+
+ * nnimap.el (nnimap-remassoc, nnimap-update-alist-soft): Moved to
+ gnus-util.
+ (nnimap-request-update-info-internal): Use new functions.
+
+ * nnml.el (nnml-request-set-mark, nnml-request-update-info): Use
+ new functions.
+
+2001-08-18 Simon Josefsson <jas@extundo.com>
+
+ Make nnml groups self-contained as far as marks are concerned.
+
+ * nnml.el (nnml-request-delete-group): Delete marks file.
+ (nnml-request-rename-group): Move marks file.
+ (nnml-marks-file-name, nnml-marks-is-evil, nnml-marks): New server
+ variables.
+ (nnml-request-set-mark, nnml-request-update-info): New server
+ functions.
+ (nnml-save-marks, nnml-open-marks): New functions.
+
+2001-08-18 Simon Josefsson <jas@extundo.com>
+
+ * gnus-sum.el (gnus-summary-move-article): Use `add' instead of
+ `set' when setting marks.
+
+2001-08-17 22:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.el (gnus-info-find-node): Take an argument.
+
+ * gnus-art.el (gnus-button-handle-info): New.
+ (gnus-url-unhex-string): Replace "+" with " ".
+
+2001-08-17 21:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-check-news-header-syntax): Check bad From.
+
+2001-08-18 00:14:45 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus-spec.el (gnus-correct-length): New function.
+ (gnus-correct-substring): New function.
+ (gnus-tilde-max-form): Use it.
+
+2001-08-17 Nevin Kapur <nevin@jhu.edu>
+
+ * nnmh.el: Docstring changes as below.
+
+ * nnml.el: Docstring changes as below.
+
+ * nnbabyl.el: Docstring changes as below.
+
+ * nnmbox.el: Docstring changes as below.
+
+ * nnfolder.el: Added docstrings identifying each virtual server
+ parameter.
+
+2001-08-18 Simon Josefsson <jas@extundo.com>
+
+ * mml.el (mml-menu): Collapse Attach, Insert and Security submenu.
+
+2001-08-17 Bj\e,Av\e(Brn Torkelsson <torkel@acc.kth.se>
+
+ * message.el: rename "Abort Message" to "Postpone Message".
+ Remove "Attach file as MIME" from Message menu, it's already in
+ the MIME menu.
+
+2001-08-17 14:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * smime.el (smime-point-at-eol): eval-and-compile.
+ (smime-make-temp-file): New.
+ (smime-sign-region, smime-encrypt-region, smime-decrypt-region):
+ Use it.
+
+2001-08-17 10:41:14 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus-agent.el (gnus-agent-fetch-group): Go online if offline.
+ (gnus-agent-summary-fetch-group): New command and keystroke.
+
+ * gnus-art.el (gnus-insert-mime-button): Tiny clean-up.
+ (gnus-mime-display-security): Make it respect
+ gnus-unbuttonized-mime-type-p.
+
+ * gnus-sum.el (gnus-articles-to-read): Comments.
+ (gnus-article-marked-p): New function.
+ (gnus-summary-display-make-predicate): New function.
+ (gnus-select-newsgroup): Use them.
+
+ * mm-decode.el (mm-save-part-to-file): Made it not error.
+
+2001-08-17 Simon Josefsson <jas@extundo.com>
+
+ * imap.el (imap-wait-for-tag): If process-status isn't open or
+ run, return nil instead of sit-for looping.
+
+2001-08-17 10:41:14 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * lpath.el (featurep): fbind xml-parse-region.
+
+ * gnus.el (gnus-message-archive-method): Default to "archive".
+ (gnus-message-archive-method): Doc fix.
+ (gnus-parameters-get-parameter): Cleaned up.
+ (gnus-expand-group-parameter): New function.
+
+ * gnus-start.el (gnus-setup-news): Push the archive server only
+ the server list.
+
+ * mml.el (mml-menu): Changed name to "Attachments".
+
+ * mm-decode.el (mm-destroy-postponed-undisplay-list): Only message
+ when there is something to detroy.
+
+2001-05-21 17:11:46 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus-srvr.el (gnus-server-browse-in-group-buffer): Default to
+ nil.
+
+2001-08-15 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus-delay.el (gnus-delay-article): Allow "01:23" time spec,
+ which specifies a time today or tomorrow.
+
+2001-08-15 Simon Josefsson <jas@extundo.com>
+ From Pavel@Janik.cz (Pavel Jan\e,Bm\e(Bk)
+
+ * gnus-agent.el (gnus-agent-make-mode-line-string)
+ (gnus-agent-toggle-plugged): Use new API.
+
+2001-08-14 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus-delay.el (gnus-delay-send-drafts): Fix check whether
+ deadline has expired.
+
+2001-08-12 Simon Josefsson <jas@extundo.com>
+ Suggested by Kai.Grossjohann@CS.Uni-Dortmund.DE
+
+ Support `recent' mark indicating newly arrived messages (to
+ separate from old but unread messages).
+
+ * nnimap.el (nnimap-retrieve-groups): Push dummy article into
+ `nnmail-split-history' if recent is > 0.
+ (nnimap-request-update-info-internal): Update `recent' marks.
+ (nnimap-request-set-mark): Never set `recent' marks.
+ (nnimap-mark-to-predicate-alist, nnimap-mark-to-flag-alist): Add
+ recent.
+
+ * gnus-sum.el (gnus-recent-mark): New mark.
+ (gnus-newsgroup-recent): New variable.
+ (gnus-summary-local-variables): Add gnus-newsgroup-recent.
+ (gnus-summary-prepare-threads): Mark recent articles.
+ (gnus-summary-add-mark): Support recent.
+ (gnus-summary-update-secondary-mark): Support recent.
+
+ * gnus.el (gnus-article-mark-lists): Add recent.
+
+2001-08-12 Simon Josefsson <jas@extundo.com>
+
+ * mm-bodies.el (mm-decode-content-transfer-encoding): Returns
+ whether successful decoding took place. Add doc.
+
+2001-08-12 Simon Josefsson <jas@extundo.com>
+ Suggested by Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * gnus.el (gnus-summary-line-format, gnus-parameters):
+ * gnus-gl.el (gnus-summary-grouplens-line-format):
+ * gnus-salt.el (gnus-summary-pick-line-format):
+ * gnus-spec.el (gnus-format-specs): %n is 23 chars.
+
+2001-08-11 09:40:00 Karl Kleinpaste <karl@charcoal.com>
+ Committed by Kai Gro\e,A_\e(Bjohann.
+
+ * gnus-score.el (gnus-score-string): Fix `match' regexp
+ for `extra' header case.
+
+2001-08-10 23:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnmbox.el (nnmbox-read-mbox): No warning.
+
+2001-08-10 21:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nndoc.el (nndoc-article-type): Fix doc.
+ (nndoc-generate-article-function): New.
+ (nndoc-dissection-function): New.
+ (nndoc-type-alist): Add oe-dbx.
+ (nndoc-oe-dbx-type-p): New.
+ (nndoc-oe-dbx-dissection): New.
+ (nndoc-oe-dbx-generate-article): New.
+
+2001-08-11 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus-delay.el (gnus-delay-send-drafts): Cleaner way to check
+ whether deadline has been reached. Patch from Dan Nicolaescu
+ <dann@godzilla.ics.uci.edu>.
+
+2001-08-10 02:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-ml.el (turn-on-gnus-mailing-list-mode): Use
+ gnus-group-find-parameter. Suggested by Janne Rinta-Manty
+ <rintaman@cs.Helsinki.FI>.
+
+ * mail-source.el (mail-source-movemail): The error buffer is
+ modified, but nothing in it.
+
+2001-08-10 01:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-bogus-system-names): New.
+ (message-make-fqdn): Use it.
+
+2001-08-09 15:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nndraft.el (nndraft-request-group): Use
+ nndraft-auto-save-file-name.
+
+2001-08-09 Simon Josefsson <jas@extundo.com>
+
+ * mm-view.el (mm-view-pkcs7-decrypt): Operate in current buffer.
+ Don't ask whether to decrypt. Just leave result in buffer (don't
+ call mm).
+
+ * mm-decode.el (mm-dissect-buffer): Possibly verify/decrypt single
+ parts as well.
+ (mm-inline-media-tests): Ignore application/{x-,}pkcs7-mime.
+ (mm-possibly-verify-or-decrypt): Support application/{x-,}pkcs7-mime.
+
+2001-08-09 Simon Josefsson <jas@extundo.com>
+
+ * mm-decode.el (mm-insert-part): Return decoding success status.
+ (mm-save-part-to-file): Error if decoding failed.
+
+2001-08-09 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-tab): Use indent-relative.
+ (message-mode): Don't bind indent-line-function to indent-relative.
+
+2001-08-09 Simon Josefsson <jas@extundo.com>
+
+ * message.el (message-get-reply-headers): Fix string. Suggested by
+ Christoph Conrad <cc@cli.de>.
+
+2001-08-08 15:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-tab): Use the current value of
+ indent-line-function.
+ (message-mode): Bind indent-line-function to indent-relative.
+
+2001-08-08 Simon Josefsson <jas@extundo.com>
+
+ * imap.el (imap-gssapi-auth-p, imap-kerberos4-auth-p): Also check
+ whether `imtest' is installed.
+
+2001-08-04 Nuutti Kotivuori <nuutti.kotivuori@smarttrust.com>
+ Committed by ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-sum.el (gnus-summary-show-article): Call
+ gnus-summary-update-secondary-secondary-mark.
+ * gnus-sum.el (gnus-summary-edit-article-done): Ditto.
+ * gnus-sum.el (gnus-summary-reparent-thread): Ditto.
+
+2001-08-07 16:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-sum.el (gnus-summary-make-menu-bar): Misc -> Gnus.
+
+ * gnus-group.el (gnus-group-make-menu-bar): Ditto.
+
+ * mm-uu.el (mm-uu-dissect): Autoload. From Gerd M\e,Av\e(Bllmann
+ <gerd@gnu.org>.
+
+ * gnus-art.el (gnus-output-to-file): Bind file-name-coding-system.
+
+ * gnus-util.el (gnus-output-to-rmail): Ditto.
+ (gnus-output-to-mail): Ditto.
+
+ * nnmail.el (nnmail-pathname-coding-system): Set default to nil.
+
+2001-08-06 Florian Weimer <fw@deneb.enyo.de>
+
+ * message.el (message-indent-citation): Use
+ `message-yank-cited-prefix' for empty lines.
+
+2001-08-05 Florian Weimer <fw@deneb.enyo.de>
+
+ * message.el (message-indent-citation): Quote only lines starting
+ with ">" using `message-yank-cited-prefix'.
+
+2001-08-05 Nuutti Kotivuori <nuutti.kotivuori@smarttrust.com>
+
+ * gnus-cache.el (gnus-cache-possibly-enter-article): Use
+ gnus-cache-fully-p.
+
+2001-08-04 Simon Josefsson <jas@extundo.com>
+
+ * gnus-cache.el (gnus-cache-possibly-update-active): Create active
+ file if it doesn't exist (by calling gnus-cache-read-active).
+
+2001-08-04 Simon Josefsson <jas@extundo.com>
+
+ * gnus-cache.el (gnus-cache-possibly-enter-article): Revert.
+ (gnus-cache-passively-or-fully-p): Removed.
+ (gnus-cache-fully-p): Fix it.
+
+ * mm-view.el (mm-pkcs7-signed-magic): Support more ASN.1 lengths.
+
+2001-08-04 Simon Josefsson <jas@extundo.com>
+
+ * gnus-cache.el (gnus-cache-fully-p)
+ (gnus-cache-passively-or-fully-p): New functions.
+ (gnus-cache-possibly-enter-article): Cosmetic change, use
+ `g-c-p-o-f-p'.
+ (gnus-cache-possibly-enter-article): Use `g-c-p-u-a'; last change
+ was bogus (`g-c-p-a-a' does not change active info, just change
+ the functions parameters).
+ (gnus-cache-possibly-remove-articles-1): Make sure articles are
+ not removed in groups that match `gnus-uncacheable-groups'.
+
+ Reported and modifications based on discussions with Nuutti
+ Kotivuori <nuutti.kotivuori@smarttrust.com>.
+
+2001-08-04 Nuutti Kotivuori <nuutti.kotivuori@smarttrust.com>
+ Committed by Simon Josefsson <jas@extundo.com>
+
+ * gnus-cache.el (gnus-cache-possibly-update-active): New function;
+ calls `gnus-cache-update-active' if bounds has been extended.
+
+2001-08-04 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-art.el (gnus-mime-security-verify-or-decrypt): Insert
+ before remove.
+ (gnus-mime-security-show-details): Ditto.
+
+2001-08-04 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * nnmail.el (nnmail-split-fancy-with-parent): Correct `mapconcat'
+ syntax. Protect string-match against nil string and regexp.
+
+2001-08-03 19:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-util.el (mm-find-charset-region): Remove control-1.
+
+2001-08-03 17:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-decode.el (mm-readable-p): Emacs 20 takes one argument.
+
+2001-08-04 Simon Josefsson <jas@extundo.com>
+
+ * smime.el (smime-sign-region, smime-encrypt-region): Fix details
+ buffer. Delete MIME-Version header.
+
+2001-08-03 Simon Josefsson <jas@extundo.com>
+
+ * gnus-cache.el (gnus-cache-possibly-enter-article): The article
+ that is entered does not necessarily have the highest article
+ number in the group, so use `gnus-cache-possibly-alter-active'
+ instead of `gnus-cache-update-active'.
+
+2001-08-03 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mml2015.el (mml2015-gpg-extract-signature-details): Don't barf.
+
+2001-08-03 Simon Josefsson <jas@extundo.com>
+
+ * mml.el (mml-menu): Rename from MML to Mime. Collapse Security
+ menu.
+
+2001-08-02 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * gnus.el (post-method): New group parameter. It also provides
+ the user option `gnus-post-method-alist' and the internal function
+ `gnus-parameter-post-method'.
+
+ * gnus-msg.el (gnus-post-method): Bind the value of
+ `gnus-post-method' to the group parameter if it is defined.
+
+2001-08-02 Simon Josefsson <jas@extundo.com>
+
+ * smime.el (smime-extra-arguments): Removed.
+ (smime-call-openssl-region): Don't use it.
+
+2001-08-02 Simon Josefsson <jas@extundo.com>
+
+ * smime.el (smime-sign-region): Handle stderr.
+ (smime-encrypt-region): Ditto.
+
+ * mm-view.el (mm-pkcs7-signed-magic): Make it a regexp. Don't
+ match the ASN.1 length bytes.
+ (mm-pkcs7-enveloped-magic): Ditto.
+ (mm-view-pkcs7-get-type): Don't regexp quote.
+
+2001-08-01 14:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ From Andreas Fuchs <asf@void.at>
+
+ * mml2015.el (mml2015-trust-boundaries-alist): Typo.
+
+2001-08-01 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-art.el (gnus-header-button-alist): References regexp.
+
+2001-08-01 Gerd Moellmann <gerd@gnu.org>
+
+ * mm-view.el (autoload): Don't autoload `diff-mode' if it's
+ already fboundp. Add INTERACTIVE arg to autoload form.
+
+2001-08-01 09:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnslashdot.el (nnslashdot-init): Add as gnus buffer.
+
+ * nnmail.el (nnmail-cache-open): Ditto.
+
+2001-07-31 21:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-art.el (gnus-button-fetch-group): Fix the regexp.
+
+2001-07-31 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * gnus-msg.el (gnus-post-method): Refer to `gnus-parameters'.
+
+2001-07-31 17:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ Originally from Pavel Jan\e,Bm\e(Bk <Pavel@Janik.cz>
+
+ * gnus-agent.el (gnus-agent-make-mode-line-string): New.
+ (gnus-agent-toggle-plugged): Use it.
+
+2001-07-31 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-start.el (gnus-startup-file-coding-system): Revert to binary.
+ (gnus-ding-file-coding-system): New variable.
+ (gnus-read-newsrc-el-file, gnus-save-newsrc-file)
+ (gnus-slave-save-newsrc): Use it.
+
+2001-07-31 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus-delay.el (gnus-delay-initialize): Use standard define-key
+ syntax.
+
+2001-07-30 15:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ Originally from Andreas Fuchs <asf@void.at>
+
+ * mml2015.el (mml2015-trust-boundaries-alist)
+ (mml2015-gpg-pretty-print-fpr): New.
+ (mml2015-gpg-extract-signature-details): More details, rename from
+ `m-g-e-from'.
+ (mml2015-gpg-verify): Use them.
+ (mml2015-gpg-clear-verify): Use them.
+
+2001-07-31 Simon Josefsson <jas@extundo.com>
+
+ * mml-smime.el (mml-smime-sign, mml-smime-encrypt): Goto end of
+ buffer when done.
+
+2001-07-30 Simon Josefsson <jas@extundo.com>
+
+ * smime.el (smime-call-openssl-region): Revert previous change,
+ just pass on buf to `call-process-region'.
+ (smime-verify-region): Doc fix. Don't message stuff. Use
+ `smime-new-details-buffer'. Inserts error messages into buffer.
+ (smime-noverify-region): Ditto.
+ (smime-decrypt-region): Ditto. Handles stderr separately.
+ (smime-verify-buffer, smime-noverify-buffer)
+ (smime-decrypt-buffer): Doc fix.
+ (smime-new-details-buffer): New function.
+ (smime-pkcs7-region, smime-pkcs7-certificates-region)
+ (smime-pkcs7-email-region): Use `smime-new-details-buffer'.
+ (smime-sign-region, smime-encrypt-region): Don't use
+ `insert-buffer'.
+
+ * mml-smime.el (mml-smime-verify): Fix security button strings.
+
+2001-07-30 12:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-art.el (gnus-mime-save-part-and-strip): Save
+ gnus-article-mime-handles.
+
+2001-07-29 Simon Josefsson <jas@extundo.com>
+
+ * mail-source.el (top-level): Require message for message-directory.
+ (mail-source-directory): Change default to message-directory.
+
+ * smime.el (smime-keys, smime-CA-directory, smime-CA-file)
+ (smime-certificate-directory, smime-openssl-program)
+ (smime-encrypt-cipher, smime-dns-server): Fix doc (leading "*").
+ (smime-extra-arguments): New variable.
+ (smime-dns-server): Fix customize group.
+ (smime-call-openssl-region): Use `smime-extra-arguments'.
+
+2001-07-29 Simon Josefsson <jas@extundo.com>
+ From Vladimir Volovich <vvv@vsu.ru>
+
+ * smime.el (smime-call-openssl-region): Ignore stderr.
+
+2001-07-29 Simon Josefsson <jas@extundo.com>
+ From Christoph Conrad <christoph.conrad@gmx.de>
+
+ * gnus-agent.el (gnus-agent-save-group-info): Don't destroy active
+ file.
+
+2001-07-29 Simon Josefsson <jas@extundo.com>
+
+ * mm-view.el (mm-view-pkcs7-decrypt): Adhere to `mm-decrypt-option'.
+
+ Support S/MIME decryption.
+
+ * mm-decode.el (mm-inline-media-tests):
+ (mm-inlined-types):
+ (mm-automatic-display):
+ (mm-attachment-override-types): Add application/{x-,}pkcs7-mime.
+
+ * mm-view.el (mm-pkcs7-signed-magic):
+ (mm-pkcs7-enveloped-magic): New variables.
+ (mm-view-pkcs7-get-type): New function; identify PKCS#7 type.
+ (mm-view-pkcs7): New function; mm viewer for PKCS#7 blobs.
+ (mm-view-pkcs7-decrypt): New function; mm viewer for encrypted
+ PKCS#7 blobs.
+
+ * smime.el (smime-decrypt-region): Expand keyfile.
+
+2001-07-29 Simon Josefsson <jas@extundo.com>
+
+ * nntp.el (nntp-open-ssl-stream): Don't mess with internal
+ `ssl.el' variables.
+
+ * gnus-agent.el (gnus-agent-save-group-info): Delete everything
+ but line instead of narrowing to it, because `nnmail-parse-active'
+ calls widen. Thanks to Christoph Conrad
+ <christoph.conrad@gmx.de>.
+
+2001-07-29 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus.el (gnus-summary-line-format): Mention `gnus-sum-thread-*'
+ for %B spec.
+
+ * gnus-sum.el (gnus-summary-prepare-threads): If
+ gnus-sum-thread-tree-root is nil, use subject instead.
+ (gnus-sum-thread-tree-root, gnus-sum-thread-tree-single-indent)
+ (gnus-sum-thread-tree-vertical, gnus-sum-thread-tree-indent)
+ (gnus-sum-thread-tree-leaf-with-other)
+ (gnus-sum-thread-tree-single-leaf): Documentation.
+ (gnus-sum-thread-tree-single-indent): Allow nil.
+
+2001-07-28 09:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-fill-paragraph): Do nothing if the user
+ wants filladapt-mode.
+
+2001-07-27 23:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-decode.el (mm-image-type-from-buffer): New.
+ (mm-get-image): Use it.
+
+2001-07-27 18:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.el (gnus-large-newsgroup): If it is nil, ...
+
+ * gnus-art.el (gnus-mime-view-all-parts): buffer-read-only covers
+ mm-display-parts too.
+
+2001-07-27 12:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnfolder.el (nnfolder-request-accept-article): Bind
+ nntp-server-buffer.
+
+ * nnmail.el (nnmail-parse-active): Read from buffer instead of
+ nntp-server-buffer.
+
+2001-07-27 11:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-check-news-header-syntax): Use
+ message-post-method.
+ (message-send-news): Bind message-post-method.
+
+2001-07-27 07:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mml.el (mml-tweak-type-alist): New.
+ (mml-tweak-function-alist): New.
+ (mml-tweak-part): New.
+ (mml-generate-mime-1): Use it.
+
+2001-07-26 22:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnfolder.el (nnfolder-request-accept-article): Replace
+ nnfolder-request-list.
+
+2001-07-27 Simon Josefsson <jas@extundo.com>
+
+ * nnimap.el (nnimap-open-server): Set nnimap-server-buffer if
+ nnoo-change-server failed to do it.
+
+2001-07-26 16:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.el (gnus-parameters): Make it customizable.
+
+2001-07-26 15:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-art.el (gnus-mm-display-part): Narrow to point if eobp.
+
+ * message.el (message-set-auto-save-file-name): More
+ poor-system-types.
+
+ * mailcap.el (mailcap-parse-mimetypes): poor-system-types.
+
+ * gnus-ems.el (nnheader-file-name-translation-alist): M$Windows-NT
+ supports +.
+
+2001-07-26 14:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-decode.el (mm-readable-p): New.
+ (mm-inline-media-tests): Fix the default testers.
+
+2001-07-26 Simon Josefsson <jas@extundo.com>
+
+ * nnimap.el (nnimap-version): Bump version number.
+
+2001-07-26 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ From Steven E. Harris <seh@speakeasy.org>
+
+ * nnheader.el (nnheader-translate-file-chars): cygwin32 is running
+ in M$Windows too.
+
+2001-07-26 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus-delay.el (gnus-delay-send-drafts): Don't `error'.
+
+2001-07-25 21:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-bcklg.el (gnus-backlog-shutdown): Make interactive.
+
+ * mm-decode.el (mm-get-image): Guess then use the type.
+
+ * gnus-art.el (gnus-mime-view-part-as-type): Don't copy cache.
+
+2001-07-25 12:54:00 Danny Siu <dsiu@adobe.com>
+
+ * gnus-sum.el (gnus-summary-prepare-threads): Shouldn't do tree
+ display (%B) for threads if threading is off.
+
+2001-07-25 14:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ From Henrik Enberg <henrik@enberg.org>
+
+ * gnus-msg.el: Customization patch.
+
+2001-07-25 22:22:22 Raymond Scholz <rscholz@zonix.de>
+
+ * nnmail.el (nnmail-split-fancy-with-parent-ignore-groups): New
+ variable.
+ (nnmail-split-fancy-with-parent): Ignore certain groups.
+
+2001-07-25 11:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-util.el (gnus-byte-compile): New.
+ (gnus-use-byte-compile): New.
+ (gnus-make-sort-function): Use it.
+
+ * nnmail.el (nnmail-get-new-mail): Use it.
+
+ * gnus-agent.el (gnus-category-make-function): Simple function or
+ compiled function.
+ (gnus-agent-fetch-group-1): Don't use (caaddr predicate).
+
+ * gnus-gl.el (bbb-build-rate-command): Remove quote before lambda.
+ * gnus-topic.el (gnus-topic-sort-topics-1): Ditto.
+ (gnus-topic-sort-topics-1): Use gnus-byte-compile.
+
+ * message.el (message-check-news-header-syntax): Remove quote.
+
+2001-07-24 19:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-use-mail-followup-to): `t' is not a
+ documented value.
+
+2001-07-24 13:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-sum.el (gnus-summary-display-arrow): Test fboundp.
+
+2001-07-24 12:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-encode.el (mm-encode-buffer): Don't use 7bit encoding if
+ there are long lines.
+
+2001-07-24 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * dgnushack.el (copy-list): New compiler macro.
+
+2001-07-24 09:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-bounce): If no Return-Path, the whole
+ content is considered as the original message.
+
+ * nnml.el (nnml-check-directory-twice): New.
+ (nnml-article-to-file): Use it.
+ (nnml-retrieve-headers): Hack it.
+
+2001-07-24 02:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-win.el (gnus-buffer-configuration): New configure.
+
+ * gnus-art.el (gnus-mm-display-part): Don't select-window if it is
+ not alive.
+
+ * mm-decode.el (mm-remove-part): Don't murder the current window (nil).
+ (mm-display-external): Use display-term configure.
+
+2001-07-24 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus-delay.el (gnus-delay-default-hour): New variable.
+ (gnus-delay-article): Allow specific date in YYYY-MM-DD format.
+
+2001-07-23 22:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ From Karl Kleinpaste <karl@charcoal.com>
+
+ * gnus-sum.el (gnus-summary-line-format-alist): Add %B.
+ (gnus-summary-prepare-threads): Ditto.
+
+ * gnus.el (gnus-summary-line-format): Add %B.
+
+2001-07-23 19:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-sum.el (gnus-articles-to-read): Use gnus-group-decoded-name.
+
+ * mm-util.el (mm-string-as-multibyte): New.
+
+ * nnmh.el (nnmh-request-list-1): Encode, not decode!
+
+2001-07-23 18:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-util.el (mm-universal-coding-system): New.
+
+ * gnus-start.el (gnus-startup-file-coding-system): Use it.
+
+ * score-mode.el (score-mode-coding-system): Use it.
+
+2001-07-23 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * gnus-start.el (gnus-setup-news): Call
+ `gnus-check-bogus-newsgroups' just after the native server is
+ opened.
+
+2001-07-23 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * nnmail.el (nnmail-do-request-post): Util function to be used by
+ `nnchoke-request-post' for all nnmail-derived backends.
+
+ * nnml.el (nnml-request-post): Use it.
+
+ * gnus.el (gnus-valid-select-methods): nnml is a post-mail
+ backend, for it groks nnml-request-post.
+
+ * gnus-group.el (gnus-group-highlight, gnus-group-highlight-line):
+ Treat `mail-post' backends like `mail' backends, not like `news'
+ backends.
+
+2001-07-22 09:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-msg.el (gnus-setup-message): make-local-hook.
+
+2001-07-22 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus-delay.el (gnus-delay-article): Fix `read-string' for
+ XEmacs. Allow more units. Submitted by Karl Kleinpaste
+ <karl@charcoal.com>, slightly changed by Kai.
+
+ * message.el (message-check-news-header-syntax): When checking
+ whether the groups exist, check the right server based on
+ `gnus-post-method'.
+
+2001-07-21 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus-delay.el: New file.
+
+2001-07-21 13:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-util.el (mm-read-coding-system): Take two arguments.
+
+ * gnus-sum.el (gnus-summary-show-article): Use
+ mm-read-coding-system.
+
+ * gnus-art.el (article-de-quoted-unreadable):
+ (article-de-base64-unreadable, article-wash-html):
+ (gnus-mime-inline-part, gnus-mime-view-part-as-charset): Ditto.
+
+2001-07-21 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * nnml.el (nnml-request-post): New function. Can be used for
+ annotations in nnml groups.
+
+2001-07-19 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * nntp.el (nntp-request-newgroups): Use UTC date for NEWGROUPS
+ command.
+
+ * gnus-start.el (gnus-find-new-newsgroups): Use
+ `message-make-date' instead of `current-time-string'.
+ (gnus-ask-server-for-new-groups): Ditto.
+ (gnus-check-first-time-used): Ditto.
+
+2001-07-20 11:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-score.el (gnus-home-score-file): nnheader-translate-file-chars.
+
+2001-07-18 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * message.el (message-shorten-references): Change `maxcount' and
+ `cut' to obey USEFOR draft 5.
+
+2001-07-12 Colin Walters <walters@cis.ohio-state.edu>
+
+ * gnus-sum.el (gnus-summary-display-arrow): New variable.
+ (gnus-summary-set-article-display-arrow): New function.
+ (gnus-summary-goto-subject): Use it.
+
+2001-07-18 12:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-sum.el (gnus-summary-import-article): Insert date if
+ doesn't exist.
+
+2001-07-18 11:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mml.el (mml-content-type-parameters): New.
+ (mml-content-disposition-parameters): New.
+ (mml-insert-mime-headers): Use them.
+ (mml-parse-1): Accept charset.
+
+2001-07-17 22:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-group.el (gnus-group-select-group): Doc fix.
+
+ * gnus-eform.el (gnus-edit-form-done): Return nil if end-of-file.
+
+2001-07-17 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * dgnushack.el (dgnushack-make-auto-load): Advise `make-autoload'
+ to handle `define-derived-mode'.
+
+2001-07-16 12:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ From: Stefan Monnier <monnier@cs.yale.edu>
+
+ * message.el (message-mode): Use define-derived-mode.
+ (message-tab): message-completion-alist.
+
+ * imap.el (imap-interactive-login): Use make-local-variable.
+ (imap-open): Ditto.
+ (imap-authenticate): Ditto.
+
+ * gnus-msg.el (gnus-setup-message): Change-major-mode-hook.
+
+ * gnus-art.el (gnus-article-edit-mode): Use define-derived-mode.
+
+2001-07-16 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * message.el (message-citation-line-function): Refer to
+ gnus-cite-attribution-suffix.
+
+2001-07-15 Pavel Jan\e,Bm\e(Bk <Pavel@Janik.cz>
+
+ * gnus-art.el,...: Error convention changes.
+
+2001-07-13 20:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-sum.el (gnus-rebuild-thread): Count hidden lines too.
+
+2001-07-13 20:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnrss.el (nnrss-read-group-data): Nuke emacs-lisp-mode-hook.
+ (nnrss-read-server-data): Ditto.
+
+2001-07-13 12:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-setup.el (gnus-use-installed-gnus): Typo.
+ * Cleanup files.
+ From Pavel@Janik.cz (Pavel Jan\e,Bm\e(Bk).
+
+2001-07-13 08:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.el (gnus-summary-line-format): Add %o.
+
+ * gnus-sum.el (gnus-summary-pipe-output): Don't configure as pipe
+ unless shell outputs something.
+
+2001-07-13 07:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-art.el (gnus-boring-article-headers): Better doc.
+ (article-hide-headers): Better regexp.
+ Suggested by Matt Swift <swift@alum.mit.edu>.
+
+ * nnheader.el (nnheader-max-head-length): Better doc.
+ (nnheader-header-value): Skip spaces.
+ (nnheader-parse-head): Remove space.
+ Suggested by Matt Swift <swift@alum.mit.edu>.
+
+ * gnus-sum.el (gnus-summary-show-raw-article): New function.
+ (gnus-get-newsgroup-headers): Remove space.
+
+2001-07-12 23:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-msg.el (gnus-msg-treat-broken-reply-to): Add force.
+ (gnus-summary-reply): Use it.
+ (gnus-summary-reply-broken-reply-to): New.
+ (gnus-msg-force-broken-reply-to): New.
+
+ * mm-view.el (mm-inline-text): Showing as text/plain when error.
+
+2001-07-12 21:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-draft.el (gnus-draft-setup): Restore gnus-newsgroup-name.
+
+2001-07-12 15:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-decode.el (mm-external-terminal-program): New variable.
+ (mm-display-external): Use it. Use term to display when no
+ window-system.
+
+2001-07-12 Bj\e,Av\e(Brn Torkelsson <torkel@hpc2n.umu.se>
+
+ * gnus-srvr.el (gnus-browse-make-menu-bar): Changed one of the
+ Browse->Next entries to Browse->Prev
+
+2001-07-11 22:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-msg.el (gnus-inews-do-gcc): Don't test gnus-alive-p.
+
+2001-07-11 18:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-encode.el (mm-content-transfer-encoding-defaults): Use base64
+ for the default encoding.
+
+ * nnrss.el (nnrss-url-field): New field.
+ (nnrss-request-article): Add newsgroups.
+
+ * nnfolder.el (nnfolder-read-folder): Force to use a multibyte buffer.
+
+2001-07-11 04:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nndraft.el (nndraft-request-restore-buffer): Don't remove Date.
+
+ * gnus-draft.el (gnus-draft-edit-message): Remove Date here.
+ (gnus-draft-setup): Remove backlog.
+
+2001-07-10 Pavel Jan\e,Bm\e(Bk <Pavel@Janik.cz>
+
+ * gnus-logic.el, gnus-srvr.el, gnus-vm.el, nnheaderxm.el, nnoo.el:
+ Cleanup.
+
+2001-07-09 23:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-msg.el (gnus-bug): Erase buffer.
+
+ * nnfolder.el (nnfolder-possibly-change-group): Don't create group.
+
+2001-07-09 19:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-decode.el (mm-attachment-override-p): Fix typo.
+
+2001-03-19 05:28:00 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * gnus-kill.el (gnus-execute): Work with the extra headers.
+ * gnus-sum.el (gnus-summary-execute-command): Ditto.
+
+2001-07-09 17:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-view.el (mm-inline-text): w3-coding-system-for-mime-charset
+ may not defined. From: Raja R Harinath <harinath@cs.umn.edu>.
+
+ * message.el (message-send-mail-real-function): New variable.
+ (message-send-mail-partially, message-send-mail):
+
+ * nngateway.el (nngateway-request-post): Use it.
+
+ * gnus-agent.el (gnus-agentize): Use it.
+
+ * nnsoup.el (nnsoup-old-functions, nnsoup-set-variables)
+ (nnsoup-revert-variables): Use it.
+
+2001-07-09 Colin Walters <walters@cis.ohio-state.edu>
+
+ * mm-decode.el (mm-inline-media-tests): Default to displaying as
+ text/plain if the type doesn't match any other media types.
+ (mm-inlined-types): Doc fix.
+ (mm-display-inline): Revert previous change (now handled by a
+ default type in `mm-inline-media-tests'.
+ (mm-inlinable-p): Revive.
+ (mm-display-part): Call `mm-inlinable-p'.
+ (mm-attachment-override-p): Ditto.
+ (mm-inlined-p): Doc fix.
+
+ * gnus-art.el (gnus-mime-display-single): Call `mm-inlinable-p' as
+ well as `mm-inlined-p'.
+
+2001-07-09 13:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nntp.el (nntp-send-command, nntp-send-command-nodelete):
+ (nntp-send-command-and-decode): Use gnus-point-at-bol.
+
+2001-07-09 13:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ From Paul Jarc <prj@po.cwru.edu>
+
+ * message.el (message-use-mail-followup-to): New variable.
+ (message-get-reply-headers): Use it.
+
+2001-07-04 Gerd Moellmann <gerd@gnu.org>
+
+ * nnheader.el (nnheader-init-server-buffer): Make sure the
+ *nntpd* buffer is made multibyte instead of a random buffer.
+
+2001-07-09 12:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-sum.el (gnus-get-newsgroup-headers-xover): Get headers only
+ when it returns headers.
+
+2001-07-07 Simon Josefsson <jas@extundo.com>
+
+ * rfc2047.el (rfc2047-encode-message-header): Skip header when
+ trying to fold. Thanks to Colin Walters
+ <walters@cis.ohio-state.edu>
+
+2001-07-06 Simon Josefsson <jas@extundo.com>
+
+ * imap.el (imap-parse-address-list, imap-parse-flag-list)
+ (imap-parse-body-extension, imap-parse-body-ext, imap-parse-body):
+ Add information in `assert's.
+
+ * nnimap.el (nnimap-possibly-change-group): Ignore uidvalidity
+ changes. (From nnimaps' point of view, `nnimap-verify-uidvalidity'
+ and `nnimap-group-overview-filename', should handle all
+ change-of-uidvalidity related issues. But there may be other
+ problems.)
+
+2001-07-05 Colin Walters <walters@cis.ohio-state.edu>
+
+ * rfc2047.el (rfc2047-encode-message-header): Don't include the
+ header name when folding.
+
+2001-07-05 Colin Walters <walters@cis.ohio-state.edu>
+
+ * mm-decode.el (mm-inlined-types): Document relationship with
+ `mm-inline-media-tests'.
+ (mm-display-inline): Default to displaying as plain text if no
+ inlining handler is available.
+ (mm-inlinable-p): Remove.
+ (mm-inlined-p): Don't call `mm-inlinable-p'.
+ (mm-automatic-display-p): Ditto.
+ (mm-attachment-override-p): Ditto.
+
+2001-07-04 Simon Josefsson <jas@extundo.com>
+
+ * nnimap.el (nnimap-importantize-dormant): New variable.
+ (nnimap-request-update-info-internal): Use it.
+ (nnimap-request-set-mark): Ditto.
+
+2001-07-04 Didier Verna <didier@lrde.epita.fr>
+
+ * nntp.el (nntp-send-command): don't pass a buffer argument to
+ `point'. Only XEmacs accepts this.
+ * nntp.el (nntp-send-command-nodelete): ditto.
+ * nntp.el (nntp-send-command-and-decode): ditto.
+
+2001-07-04 Didier Verna <didier@lrde.epita.fr>
+
+ * nntp.el (nntp-open-connection-function): doc update.
+ * nntp.el (nntp-pre-command): New.
+ * nntp.el (nntp-via-rlogin-command): New.
+ * nntp.el (nntp-via-telnet-command): New.
+ * nntp.el (nntp-via-telnet-switches): New.
+ * nntp.el (nntp-via-user-name): New.
+ * nntp.el (nntp-via-user-password): New.
+ * nntp.el (nntp-via-address): New.
+ * nntp.el (nntp-via-envuser): New.
+ * nntp.el (nntp-via-shell-prompt): New.
+ * nntp.el (nntp-open-telnet-stream): New.
+ * nntp.el (nntp-open-via-rlogin-and-telnet): New.
+ * nntp.el (nntp-open-via-telnet-and-telnet): New.
+ * nntp.el (nntp-wait-for): check for possibly echo'ed commands.
+ * nntp.el (nntp-send-command): ditto.
+ * nntp.el (nntp-send-command-nodelete): ditto.
+ * nntp.el (nntp-send-command-and-decode): ditto.
+
+2001-06-30 YAGI Tatsuya <yagi@is.titech.ac.jp>
+
+ * gnus-start.el (gnus-check-first-time-used): Use `if' instead of
+ `when'.
+
+2001-07-03 Simon Josefsson <jas@extundo.com>
+ From Nuutti Kotivuori <nuutti.kotivuori@smarttrust.com>
+
+ * flow-fill.el (fill-flowed): Use (1+ (point-at-eol)) instead.
+
+2001-07-03 Simon Josefsson <jas@extundo.com>
+
+ * flow-fill.el (fill-flowed): If `fill-region' inserts empty line,
+ remove it (workaround XEmacs `fill-region' bug).
+
+2001-07-01 Simon Josefsson <jas@extundo.com>
+
+ * nnimap.el (nnimap-date-days-ago): Defeat locale.
+
+2001-06-28 11:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mml2015.el (mml2015-format-error): New function.
+ (mml2015-mailcrypt-decrypt, mml2015-mailcrypt-clear-decrypt)
+ (mml2015-mailcrypt-verify, mml2015-gpg-clear-verify)
+ (mml2015-mailcrypt-clear-verify, mml2015-gpg-verify): Use it.
+
+2001-06-26 22:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnrss.el (nnrss-retrieve-headers): The description may not exist.
+ Suggested by Christoph Conrad <C.Conrad@cli.de>.
+
+ * gnus-sum.el (gnus-summary-set-local-parameters): Don't override
+ group variables.
+
+2001-06-25 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnslashdot.el (nnslashdot-write-groups): Use gnus-prin1.
+
+ * nnrss.el (nnrss-save-server-data): Bind print-level and print-length.
+ (nnrss-save-group-data): Ditto.
+
+ * gnus-agent.el (gnus-agent-save-alist): Ditto.
+
+2001-06-25 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * message.el (message-do-send-housekeeping): Narrow to headers.
+
+2001-06-24 Simon Josefsson <jas@extundo.com>
+
+ * rfc2047.el (rfc2047-fold-region): The check to skip WSP
+ insertion when breaking lines looked for " \t" instead of "[ \t]".
+ (rfc2047-encode-message-header): Fold lines even if
+ no QP encoding is done.
+
+2001-06-23 Simon Josefsson <jas@extundo.com>
+ From Samuel Tardieu <sam@inf.enst.fr>
+
+ * smime.el (smime-keys): Support additional certificates.
+ (smime-make-certfiles): New function.
+ (smime-sign-region): Use previous variables.
+ (smime-get-certfiles): New function.
+ (smime-sign-buffer): Use it.
+ (smime-verify-region): Support both CAfile and CApath.
+
+2001-06-23 Simon Josefsson <jas@extundo.com>
+
+ * smime.el (smime-decrypt-region): Perhaps work.
+
+2001-06-22 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-msg.el (gnus-copy-article-buffer): Typo.
+
+2001-04-06 Ralph Schleicher <rs@nunatak.allgaeu.org>
+
+ * mm-decode.el (mm-save-part): Rewrite file name.
+ (mm-file-name-rewrite-functions): New variable.
+ (mm-file-name-delete-whitespace): New function.
+ (mm-file-name-trim-whitespace): New function.
+ (mm-file-name-collapse-whitespace): New function.
+ (mm-file-name-replace-whitespace): New variable and function.
+
+2001-06-22 Simon Josefsson <jas@extundo.com>
+
+ * message.el (message-make-date): Workaround locale for weekdays.
+
+2001-06-21 17:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-goto-body): Return nil if not found. (revert!)
+
+2001-06-21 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ From Fremlin <chief@bandits.org>
+
+ * message.el (message-goto-body): Some messages have no header.
+
+ * gnus-msg.el (gnus-copy-article-buffer): Use it.
+
+2001-06-21 Ralph Schleicher <rs@nunatak.allgaeu.org>
+
+ * nnultimate.el (nnultimate-retrieve-headers): Date fix.
+
+2001-06-21 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-make-date): Add week day.
+ Suggested by Jason R. Mastaler <jason@mastaler.com>.
+
+2001-06-19 Simon Josefsson <jas@extundo.com>
+
+ * message.el (message-yank-prefix): Doc fix.
+ (message-yank-cited-prefix): Ditto.
+ (message-delete-not-region): Keep citation prefix on first line,
+ if possible and appropriate.
+
+2001-06-19 Simon Josefsson <jas@extundo.com>
+
+ * imap.el (imap-process-connection-type): New variable.
+ (imap-kerberos4-open, imap-gssapi-open): Use it. This makes
+ recent `imtest's work completely (no line length issues), while
+ making making old `imtest's unusable. Thanks to NAGY Andras
+ <nagya@inf.elte.hu> for his work.
+
+2000-12-30 NAGY Andras <nagya@inf.elte.hu>
+
+ * imap.el (imap-ssl-program): Add -quiet to shut up
+ OpenSSL/SSLeay's internal debug talk.
+
+2001-06-19 Matt Armstrong <matt@lickey.com>
+
+ * imap.el (imap-parse-flag-list): Workaround bug in Courier IMAP
+ server.
+
+2001-06-19 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnmail.el (nnmail-article-buffer): New variable.
+ (nnmail-split-incoming): Use it.
+
+2001-06-15 Eli Zaretskii <eliz@is.elta.co.il>
+
+ * qp.el (quoted-printable-decode-region): If called interactively,
+ use coding-system-for-read.
+
+2001-06-16 09:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-check-news-header-syntax): Check Reply-To.
+
+2001-06-16 08:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mml.el (mml-parse-1): Use message options.
+
+ * message.el (message-do-fcc): Don't do anything if there is no
+ FCC.
+
+2001-06-16 Simon Josefsson <jas@extundo.com>
+
+ * nnimap.el (nnimap-split-articles): Support 'junk to-groups.
+ (nnimap-expunge-search-string): New variable.
+ (nnimap-request-expire-articles): Use it.
+
+2001-06-15 19:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-send-mail-with-qmail): wrong exit status is
+ 100 not 1. Reported by Paul Jarc <prj@po.cwru.edu>.
+
+2001-06-15 09:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-art.el (article-strip-multiple-blank-lines): Use
+ delete-region instead of replace-match.
+
+2001-06-14 16:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnweb.el (nnweb-google-parse-1): Fix Google content regexp.
+ (nnweb-google-wash-article): Ditto.
+
+2001-06-14 Ferenc Wagner <wferi@bolyai1.elte.hu>
+
+ * nnweb.el (nnweb-google-parse-1): Fix Google url regexp.
+
+2001-06-13 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * gnus.el (gnus-define-group-parameter): Don't quote the defcustom
+ specs.
+
+2001-06-13 15:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.el (gnus-email-address): Move it here.
+
+ * gnus-art.el (article-de-quoted-unreadable): Read charset if
+ requested.
+ (article-de-base64-unreadable): Ditto.
+ (article-wash-html): Ditto.
+
+2001-06-12 14:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-options-set-recipient): Don't add ", "
+ unless necessary. Suggested by Josh Huber <huber@alum.wpi.edu>.
+
+2001-06-12 12:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnrss.el (nnrss-group-alist): Use |fr| instead of [fr].
+
+2001-06-12 11:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-art.el (gnus-plain-save-name): Use file-relative-name.
+ From Marc Lefranc <Marc.Lefranc@univ-lille1.fr>.
+
+ * nnrss.el (nnrss-node-text): Node might be nil.
+
+2001-06-11 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-uu.el (gnus-uu-save-article): Use mml tag instead of
+ part. From Katsumi Yamaoka <yamaoka@jpl.org>.
+
+ * nnrss.el (nnrss-group-alist): More items.
+
+2001-06-09 23:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnrss.el (nnrss-node-text): Use cddr instead xml-node-children.
+
+2001-06-03 Dale Hagglund <rdh@best.com>
+
+ * gnus-mlspl.el (gnus-group-split-fancy): Fix generation of split
+ restrict clauses.
+
+2001-06-07 16:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ From Benjamin Rutt <brutt+news@bloomington.in.us>
+
+ * message.el (message-wide-reply-confirm-recipients): New variable.
+
+2001-06-06 Mark Thomas <mthomas@edrc.cmu.edu>
+
+ * nnmail.el (nnmail-fix-eudora-headers): Change the In-Reply-To
+ fix so it works with XEmacs.
+
+2001-06-07 16:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnrss.el (nnrss-retrieve-headers): Support description as extra
+ headers.
+
+2001-06-07 15:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnrss.el: Fix a few bugs.
+
+2001-06-05 Simon Josefsson <jas@extundo.com>
+
+ * mm-decode.el (mm-handle-set-external-undisplayer): Don't
+ generate compiler warnings. From Alex Schroeder <alex@gnu.org>.
+
+2001-06-04 Hrvoje Niksic <hniksic@arsdigita.com>
+
+ * mm-decode.el (mm-pipe-part): Bind coding-system-for-write to
+ binary so that we don't transmit ISO 2022 garbage to the process.
+ This is needed under XEmacs.
+
+2001-06-03 Simon Josefsson <simon@josefsson.org>
+
+ * imap.el (imap-ssl-open): Require ssl. (Otherwise ssl.el is
+ autoloaded incorrectly below because ssl-program-* is bound.)
+ Thanks to Amos Gouaux for report.
+
+2001-06-02 Simon Josefsson <simon@josefsson.org>
+
+ * imap.el (imap-kerberos4-open):
+ (imap-gssapi-open):
+ (imap-ssl-open):
+ (imap-network-open):
+ (imap-shell-open):
+ (imap-starttls-open): Set buffer to workaround spurious
+ `accept-process-output' buffer changes. Thanks to Mats Lidell
+ <Mats.Lidell@contactor.se> for report and partial patch and Jake
+ Colman <colman@ppllc.com> for report.
+
+2001-05-31 13:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-sum.el (gnus-summary-catchup): New argument.
+ (gnus-summary-catchup-from-here): New function.
+
+2001-05-30 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * mm-view.el (mm-inline-image-xemacs): Insert newline, then move
+ back, then insert glyph. (Before, the glyph was inserted first,
+ then the newline.) This works around a behavior in XEmacs where
+ it is not possible to insert a character after a glyph which is at
+ the end of a buffer. Patch by Lloyd Zusman <ljz@asfast.com>.
+
+2001-05-28 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ From Jaap-Henk Hoepman (jhh@xs4all.nl).
+
+ * mm-decode.el (mm-keep-viewer-alive-types): New variable.
+ (mm-keep-viewer-alive-p, mm-handle-set-external-undisplayer,
+ mm-destroy-postponed-undisplay-list): New functions.
+ (mm-display-external): Use them.
+
+2001-05-27 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus-salt.el (gnus-tree-highlight-node): Bind `default-high' and
+ `default-low' when evaluating `gnus-summary-highlight'.
+ From Raja R Harinath <harinath@cs.umn.edu>.
+
+2001-05-27 Simon Josefsson <simon@josefsson.org>
+
+ * message.el (message-yank-cited-prefix): New variable.
+ (message-indent-citation): Use it.
+
+ * mml2015.el (mml2015-mailcrypt-verify): Store gpg stderr output
+ as details.
+ (mml2015-mailcrypt-clear-verify): Ditto.
+
+2001-05-24 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+ From Nevin Kapur <nevin@jhu.edu>.
+
+ * gnus-sum.el (gnus-summary-default-high-score,
+ gnus-summary-default-low-score): New variables.
+ (gnus-summary-highlight): Use them.
+
+2001-05-16 Didier Verna <didier@lrde.epita.fr>
+
+ * message.el (message-mail): pass the 'send-actions argument to
+ `message-setup'.
+
+2001-05-16 Simon Josefsson <simon@josefsson.org>
+ From Raymond Scholz <ray-2001@zonix.de>
+
+ * gnus-art.el (gnus-mime-view-part-as-charset):
+ (gnus-mime-internalize-part): Doc fixes.
+
+2001-05-11 Simon Josefsson <simon@josefsson.org>
+
+ * gnus-start.el (gnus-ignored-newsgroups): Also ignore NNTP type
+ status lines without any text ("^215$").
+
+2001-05-06 21:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnrss.el (nnrss-check-group): Reverse.
+
+2001-05-07 Simon Josefsson <simon@josefsson.org>
+
+ * message.el (message-get-reply-headers):
+ (message-followup): Fix typo, suggested by David Green
+ <dgreen@uab.edu>
+
+2001-05-05 15:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnslashdot.el (nnslashdot-request-expire-articles): Fix.
+
+ * nnrss.el (nnrss-open-server): Read server data when it is called.
+ (nnrss-request-expire-articles): Fix.
+
+2001-05-05 09:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-do-send-housekeeping): mail-abbrevs may
+ rename buffer behind Gnus.
+
+2001-05-04 14:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnrss.el (nnrss-check-group): Use nnheader-translate-file-chars.
+ (nnrss-group-alist): Add more resources.
+ (nnrss-check-group): Ignore errors.
+
+2001-05-04 00:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnrss.el (nnrss-request-expire-articles): Correct the return value.
+
+ * nnslashdot.el (nnslashdot-request-list): Add time.
+ (nnslashdot-request-expire-articles): New.
+
+ * gnus-start.el (gnus-check-bogus-newsgroups): Remove bogus
+ secondary methods too.
+
+2001-05-03 23:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-use-followup-to): Set default value to t.
+
+2001-05-03 Florian Weimer <fw@deneb.enyo.de>
+
+ * message.el (message-dont-reply-to-names): Fix documentation.
+ (message-get-reply-headers): Use Mail-Followup-To only for wide
+ replies.
+
+2001-05-03 12:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * nnrss.el (nnrss-request-expire-articles): Calculate # of days
+ correctly.
+ (nnrss-check-group): Use time.
+
2001-05-01 19:21:19 Lars Magne Ingebrigtsen <lars@ingebrigtsen.no>
* gnus.el: Oort Gnus v0.03 is released.
2001-04-15 14:55:03 Lars Magne Ingebrigtsen <larsi@gnus.org>
* nnultimate.el (nnultimate-retrieve-headers): Return all
- available headers.
+ available headers.
* gnus-sum.el (gnus-read-all-available-headers): New variable.
(gnus-get-newsgroup-headers-xover): Use it.
gnus-newsrc-file-version may be nil.
* nnmail.el (nnmail-get-new-mail): Use the exact file only.
- Suggested by Michael Sperber [Mr. Preprocessor]
+ Suggested by Michael Sperber [Mr. Preprocessor]
<sperber@informatik.uni-tuebingen.de>.
2001-04-25 Per Abrahamsen <abraham@dina.kvl.dk>
* gnus-sum.el (gnus-summary-find-matching): Clean up.
(gnus-find-matching-articles): New function.
- (gnus-summary-limit-include-matching-articles): New command.
+ (gnus-summary-limit-include-matching-articles): New command.
(gnus-summary-limit-include-thread): Include articles that have
matching subjects.
(gnus-offer-save-summaries): Clean up.
* gnus-msg.el (gnus-post-news): Fill the Newsgroups header by the
newsgroup names when the original article is a news message.
-
+
2001-04-12 19:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
* message.el (message-cite-prefix-regexp): Use POSIX regexp if
2001-04-05 21:43:25 Lars Magne Ingebrigtsen <larsi@gnus.org>
* gnus-sum.el (gnus-update-summary-mark-positions): Use a valid
- date.
+ date.
2001-04-04 16:13:17 Lars Magne Ingebrigtsen <larsi@gnus.org>
* gnus-group.el (gnus-group-quit): Check that the dribble buffer
- lives.
+ lives.
2001-04-02 00:40:12 Lars Magne Ingebrigtsen <larsi@gnus.org>
* gnus-group.el (gnus-group-quit): Only mark buffer in non-empty.
* gnus-start.el (gnus-read-newsrc-el-file): Nix out
- gnus-format-specs.
+ gnus-format-specs.
* message.el (message-check-news-header-syntax): Question even
when Gnus doesn't know the group names.
* gnus-score.el (gnus-score-orphans): Clean up.
- * gnus-win.el (gnus-remove-some-windows): Leave one Gnus window.
+ * gnus-win.el (gnus-remove-some-windows): Leave one Gnus window.
* gnus-sum.el (gnus-summary-exit): Kill the summary buffer a bit
- later.
+ later.
* gnus-start.el (gnus-close-all-servers): Find the right items to
- close.
+ close.
* qp.el (quoted-printable-decode-region): Just message
malformation; don't quit.
`assq-delete-all', if that function exists; otherwise use the old
definition. Documentation changed to match the one in
`assq-delete-all'.
-
+
2001-04-01 00:37:14 Lars Magne Ingebrigtsen <larsi@gnus.org>
* gnus-start.el (gnus-close-all-servers): New function.
(gnus-server-remove-denials): Clean up.
* gnus-sum.el (gnus-summary-sort-by-original): New command and
- keystroke.
+ keystroke.
2001-03-31 02:56:55 Lars Magne Ingebrigtsen <larsi@gnus.org>
* mm-decode.el (mm-default-directory): Customized.
(mm-tmp-directory): Ditto.
- * gnus-sum.el (gnus-summary-catchup-and-exit): Doc fix.
+ * gnus-sum.el (gnus-summary-catchup-and-exit): Doc fix.
(gnus-get-newsgroup-headers): Return -1 for articles without Lines
- or Chars.
+ or Chars.
(gnus-summary-line-format-alist): ?l is now a string.
(gnus-summary-prepare-threads): Output ? for unknown lines.
(gnus-summary-insert-line): Ditto.
when forcing news.
* gnus-sum.el (gnus-summary-mark-article-as-replied): Make into a
- command.
+ command.
2001-03-31 01:04:54 Francis Litterio <franl-removethis@world.omitthis.std.com>
* gnus-msg.el (gnus-put-message): Clean up.
(gnus-summary-reply): Mark all replied-to articles as replied to.
(gnus-inews-add-send-actions): Also mark as forwarded.
- (gnus-summary-mail-forward): Mark as forwarded.
+ (gnus-summary-mail-forward): Mark as forwarded.
* gnus-sum.el (gnus-summary-mark-article-as-replied): Take a list
- of articles.
+ of articles.
(gnus-summary-mark-article-as-forwarded): Ditto.
* gnus-msg.el (gnus-summary-resend-message): Mark article as
- forwarded.
+ forwarded.
(gnus-summary-mail-forward): Clean up.
* gnus.el (gnus-article-mark-lists): Added forward.
(gnus-summary-very-wide-reply): New command and keystroke.
(gnus-summary-very-wide-reply-with-original): Ditto.
- * gnus-score.el (gnus-adaptive-word-length-limit): New variable.
+ * gnus-score.el (gnus-adaptive-word-length-limit): New variable.
(gnus-score-adaptive): Use it.
* gnus-start.el (gnus-get-unread-articles): Clean up.
2001-03-21 20:00:43 Lars Magne Ingebrigtsen <larsi@gnus.org>
* nnultimate.el (nnultimate-retrieve-headers): Work for other
- boards.
+ boards.
2001-03-21 Didier Verna <didier@lrde.epita.fr>
2001-03-10 Matthias Wiehl <mwiehl@gmx.de>
- * gnus.el (gnus-summary-line-format): Typo.
+ * gnus.el (gnus-summary-line-format): Typo.
2001-03-11 Simon Josefsson <simon@josefsson.org>
(nnml-request-regenerate): Use it. Change to deffoo.
2001-02-14 Katsumi Yamaoka <yamaoka@jpl.org>
- Committed by ShengHuo ZHU <zsh@cs.rochester.edu>
+ Committed by ShengHuo ZHU <zsh@cs.rochester.edu>
* gnus.el (gnus-define-group-parameter): Fix.
2001-01-19 Simon Josefsson <sj@extundo.com>
- * gnus-art.el (gnus-button-alist): Add `?=' to mailto URL regexp.
+ * gnus-art.el (gnus-button-alist): Add `?=' to mailto URL regexp.
2001-01-19 13:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
URLDIR = @URL@
EMACS_COMP = URLDIR=$(URLDIR) W3DIR=$(W3DIR) lispdir=$(lispdir) srcdir=$(srcdir) $(EMACS) $(FLAGS)
-all total: clean-some gnus-load.elc
+all total: clean-some gnus-load.el
$(EMACS_COMP) -f dgnushack-compile
clean-some:
rm -f *.elc gnus-load.el
-warn: clean-some gnus-load.elc
+warn: clean-some gnus-load.el
$(EMACS_COMP) --eval '(dgnushack-compile t)' 2>&1 | egrep -v "variable G|inhibit-point-motion-hooks|coding-system|temp-results|variable gnus|variable nn|scroll-in-place|deactivate-mark|filladapt-mode|byte-code-function-p|print-quoted|ps-right-header|ps-left-header|article-inhibit|print-escape|ssl-program-arguments|message-log-max"
# The "clever" rule is unsafe, since redefined macros are loaded from
# .elc files, and not the .el file.
-clever some: gnus-load.elc
+clever some: gnus-load.el
$(EMACS_COMP) -f dgnushack-compile
-install: clever
- rm -f dgnushack.elc
+install: install-el install-elc
+
+install-el: gnus-load.el
$(SHELL) $(top_srcdir)/mkinstalldirs $(lispdir)
+ echo " $(INSTALL_DATA) gnus-load.el $(lispdir)/gnus-load.el"
+ $(INSTALL_DATA) gnus-load.el $(lispdir)/gnus-load.el
for p in *.elc; do \
- echo " $(INSTALL_DATA) $$p $(lispdir)/$$p"; \
- $(INSTALL_DATA) $$p $(lispdir)/$$p; \
+ p=`basename $$p c`; \
+ if [ -f "$(srcdir)/$$p" ]; then \
+ echo " $(INSTALL_DATA) $$p $(lispdir)/$$p"; \
+ $(INSTALL_DATA) $(srcdir)/$$p $(lispdir)/$$p; \
+ fi; \
done
-install-el:
+install-elc: clever
+ rm -f dgnushack.elc
$(SHELL) $(top_srcdir)/mkinstalldirs $(lispdir)
- cd $(srcdir) \
- && for p in *.el; do \
+ for p in *.elc; do \
echo " $(INSTALL_DATA) $$p $(lispdir)/$$p"; \
$(INSTALL_DATA) $$p $(lispdir)/$$p; \
done
+uninstall:
+ for p in *.elc; do \
+ rm -f "$(lispdir)/$$p"; \
+ done
+ cd $(srcdir); \
+ for p in *.el; do \
+ rm -f "$(lispdir)/$$p"; \
+ done
+
tags:
etags *.el
pot:
xpot -drgnus -r`cat ./version` *.el > rgnus.pot
-gnus-load.elc:
+gnus-load.el:
$(EMACS_COMP) -f dgnushack-make-cus-load $(srcdir)
$(EMACS_COMP) -f dgnushack-make-auto-load $(srcdir)
$(EMACS_COMP) -f dgnushack-make-load
-;;; binhex.el -- elisp native binhex decode
-;; Copyright (c) 1998, 1999, 2000 Free Software Foundation, Inc.
+;;; binhex.el --- elisp native binhex decode
+;; Copyright (c) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
;; Author: Shenghuo Zhu <zsh@cs.rochester.edu>
;; Keywords: binhex news
;;; Code:
+(autoload 'executable-find "executable")
+
(eval-when-compile (require 'cl))
(eval-and-compile
'char-int
'identity)))
-(defvar binhex-decoder-program "hexbin"
+(defcustom binhex-decoder-program "hexbin"
"*Non-nil value should be a string that names a uu decoder.
The program should expect to read binhex data on its standard
-input and write the converted data to its standard output.")
+input and write the converted data to its standard output."
+ :type 'string
+ :group 'gnus-extract)
+
+(defcustom binhex-decoder-switches '("-d")
+ "*List of command line flags passed to the command named by binhex-decoder-program."
+ :group 'gnus-extract
+ :type '(repeat string))
-(defvar binhex-decoder-switches '("-d")
- "*List of command line flags passed to the command named by binhex-decoder-program.")
+(defcustom binhex-use-external
+ (executable-find binhex-decoder-program)
+ "*Use external binhex program."
+ :group 'gnus-extract
+ :type 'boolean)
(defconst binhex-alphabet-decoding-alist
'(( ?\! . 0) ( ?\" . 1) ( ?\# . 2) ( ?\$ . 3) ( ?\% . 4) ( ?\& . 5)
(t
(binhex-insert-char (setq binhex-last-char char) 1 ignored buffer))))
-(defun binhex-decode-region (start end &optional header-only)
- "Binhex decode region between START and END.
+;;;###autoload
+(defun binhex-decode-region-internal (start end &optional header-only)
+ "Binhex decode region between START and END without using an external program.
If HEADER-ONLY is non-nil only decode header and return filename."
(interactive "r")
(let ((work-buffer nil)
(and work-buffer (kill-buffer work-buffer)))
(if header (aref header 1))))
+;;;###autoload
(defun binhex-decode-region-external (start end)
"Binhex decode region between START and END using external decoder."
(interactive "r")
(let ((cbuf (current-buffer)) firstline work-buffer status
(file-name (expand-file-name
- (concat (binhex-decode-region start end t) ".data")
+ (concat (binhex-decode-region-internal start end t)
+ ".data")
binhex-temporary-file-directory)))
(save-excursion
(goto-char start)
(ignore-errors
(if file-name (delete-file file-name))))))
+;;;###autoload
+(defun binhex-decode-region (start end)
+ "Binhex decode region between START and END."
+ (interactive "r")
+ (if binhex-use-external
+ (binhex-decode-region-external start end)
+ (binhex-decode-region-internal start end)))
+
(provide 'binhex)
;;; binhex.el ends here
--- /dev/null
+;;; canlock.el --- functions for Cancel-Lock feature
+;; Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
+
+;; Author: Katsumi Yamaoka <yamaoka@jpl.org>
+;; Keywords: news, cancel-lock, hmac, sha1, rfc2104
+
+;; 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 2, 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; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; Canlock is a library for generating and verifying Cancel-Lock and/or
+;; Cancel-Key header in news articles. This is used to protect articles
+;; from rogue cancel, supersede or replace attacks. The method is based
+;; on draft-ietf-usefor-cancel-lock-01.txt which was released on November
+;; 3rd 1998. For instance, you can add Cancel-Lock (and possibly Cancel-
+;; Key) header in a news article by using a hook which will be evaluated
+;; just before sending an article as follows:
+;;
+;; (add-hook '*e**a*e-header-hook 'canlock-insert-header t)
+;;
+;; Verifying Cancel-Lock is mainly a function of news servers, however,
+;; you can verify your own article using the command `canlock-verify' in
+;; the (raw) article buffer. You will be prompted for the password for
+;; each time if the option `canlock-password' or `canlock-password-for-
+;; verify' is nil. Note that setting these options is a bit unsafe.
+
+;;; Code:
+
+(defconst canlock-version "0.8")
+
+(eval-when-compile
+ (require 'cl))
+
+(autoload 'sha1-binary "sha1-el")
+
+(defgroup canlock nil
+ "The Cancel-Lock feature."
+ :group 'applications)
+
+(defcustom canlock-sha1-function 'sha1-binary
+ "Function to call to make a SHA-1 message digest."
+ :type '(radio (function-item sha1-binary)
+ (function-item canlock-sha1-with-openssl)
+ (function :tag "Other"))
+ :group 'canlock)
+
+(defcustom canlock-sha1-function-for-verify canlock-sha1-function
+ "Function to call to make a SHA-1 message digest for verifying."
+ :type '(radio (function-item sha1-binary)
+ (function-item canlock-sha1-with-openssl)
+ (function :tag "Other"))
+ :group 'canlock)
+
+(defcustom canlock-openssl-program "openssl"
+ "Name of OpenSSL program."
+ :type 'string
+ :group 'canlock)
+
+(defcustom canlock-openssl-args '("sha1")
+ "Arguments passed to the OpenSSL program."
+ :type 'sexp
+ :group 'canlock)
+
+(defcustom canlock-ignore-errors nil
+ "If non-nil, ignore any error signals."
+ :type 'boolean
+ :group 'canlock)
+
+(defcustom canlock-password nil
+ "Password to use when signing a Cancel-Lock or a Cancel-Key header."
+ :type 'string
+ :group 'canlock)
+
+(defcustom canlock-password-for-verify canlock-password
+ "Password to use when verifying a Cancel-Lock or a Cancel-Key header."
+ :type 'string
+ :group 'canlock)
+
+(defcustom canlock-force-insert-header nil
+ "If non-nil, insert a Cancel-Lock or a Cancel-Key header even if the
+buffer does not look like a news message."
+ :type 'boolean
+ :group 'canlock)
+
+(defun canlock-sha1-with-openssl (message)
+ "Make a SHA-1 digest of MESSAGE using OpenSSL."
+ (let (default-enable-multibyte-characters)
+ (with-temp-buffer
+ (let ((coding-system-for-read 'binary)
+ (coding-system-for-write 'binary)
+ selective-display
+ (case-fold-search t))
+ (insert message)
+ (apply 'call-process-region (point-min) (point-max)
+ canlock-openssl-program t t nil canlock-openssl-args)
+ (goto-char (point-min))
+ (insert "\"")
+ (while (re-search-forward "[0-9a-f][0-9a-f]" nil t)
+ (replace-match (concat "\\\\x" (match-string 0))))
+ (insert "\"")
+ (goto-char (point-min))
+ (read (current-buffer))))))
+
+(defvar canlock-read-passwd nil)
+(defun canlock-read-passwd (prompt &rest args)
+ "Read a password using PROMPT.
+If ARGS, PROMPT is used as an argument to `format'."
+ (let ((prompt
+ (if args
+ (apply 'format prompt args)
+ prompt)))
+ (unless canlock-read-passwd
+ (if (or (fboundp 'read-passwd) (load "passwd" t))
+ (setq canlock-read-passwd 'read-passwd)
+ (unless (fboundp 'ange-ftp-read-passwd)
+ (autoload 'ange-ftp-read-passwd "ange-ftp"))
+ (setq canlock-read-passwd 'ange-ftp-read-passwd)))
+ (funcall canlock-read-passwd prompt)))
+
+(defun canlock-make-cancel-key (message-id password)
+ "Make a Cancel-Key header."
+ (cond ((> (length password) 20)
+ (setq password (funcall canlock-sha1-function password)))
+ ((< (length password) 20)
+ (setq password (concat
+ password
+ (make-string (- 20 (length password)) 0)))))
+ (setq password (concat password (make-string 44 0)))
+ (let ((ipad (mapconcat (lambda (char)
+ (char-to-string (logxor 54 char)))
+ password ""))
+ (opad (mapconcat (lambda (char)
+ (char-to-string (logxor 92 char)))
+ password "")))
+ (base64-encode-string (funcall canlock-sha1-function
+ (concat
+ opad
+ (funcall canlock-sha1-function
+ (concat ipad message-id)))))))
+
+(defun canlock-narrow-to-header ()
+ "Narrow the buffer to the head of the message."
+ (let (case-fold-search)
+ (narrow-to-region
+ (goto-char (point-min))
+ (goto-char (if (re-search-forward
+ (format "^$\\|^%s$"
+ (regexp-quote mail-header-separator))
+ nil t)
+ (match-beginning 0)
+ (point-max))))))
+
+(defun canlock-delete-headers ()
+ "Delete Cancel-Key or Cancel-Lock headers in the narrowed buffer."
+ (let ((case-fold-search t))
+ (goto-char (point-min))
+ (while (re-search-forward "^Cancel-\\(Key\\|Lock\\):" nil t)
+ (delete-region (match-beginning 0)
+ (if (re-search-forward "^[^\t ]" nil t)
+ (goto-char (match-beginning 0))
+ (point-max))))))
+
+(defun canlock-fetch-fields (&optional key)
+ "Return a list of the values of Cancel-Lock header.
+If KEY is non-nil, look for a Cancel-Key header instead. The buffer
+is expected to be narrowed to just the headers of the message."
+ (let ((field (mail-fetch-field (if key "Cancel-Key" "Cancel-Lock")))
+ fields rest
+ (case-fold-search t))
+ (when field
+ (setq fields (split-string field "[\t\n\r ,]+"))
+ (while fields
+ (when (string-match "^sha1:" (setq field (pop fields)))
+ (push (substring field 5) rest)))
+ (nreverse rest))))
+
+(defun canlock-fetch-id-for-key ()
+ "Return a Message-ID in Cancel, Supersedes or Replaces header.
+The buffer is expected to be narrowed to just the headers of the
+message."
+ (or (let ((cancel (mail-fetch-field "Control")))
+ (and cancel
+ (string-match "^cancel[\t ]+\\(<[^\t\n @<>]+@[^\t\n @<>]+>\\)"
+ cancel)
+ (match-string 1 cancel)))
+ (mail-fetch-field "Supersedes")
+ (mail-fetch-field "Replaces")))
+
+;;;###autoload
+(defun canlock-insert-header (&optional id-for-key id-for-lock password)
+ "Insert a Cancel-Key and/or a Cancel-Lock header if possible."
+ (let (news control key-for-key key-for-lock)
+ (save-excursion
+ (save-restriction
+ (canlock-narrow-to-header)
+ (when (setq news (or canlock-force-insert-header
+ (mail-fetch-field "Newsgroups")))
+ (unless id-for-key
+ (setq id-for-key (canlock-fetch-id-for-key)))
+ (if (and (setq control (mail-fetch-field "Control"))
+ (string-match
+ "^cancel[\t ]+\\(<[^\t\n @<>]+@[^\t\n @<>]+>\\)"
+ control))
+ (setq id-for-lock nil)
+ (unless id-for-lock
+ (setq id-for-lock (mail-fetch-field "Message-ID"))))
+ (canlock-delete-headers)
+ (goto-char (point-max))))
+ (when news
+ (if (not (or id-for-key id-for-lock))
+ (message "There are no Message-ID(s)")
+ (unless password
+ (setq password (or canlock-password
+ (canlock-read-passwd
+ "Password for Canlock: "))))
+ (if (or (not (stringp password)) (zerop (length password)))
+ (message "Password for Canlock is bad")
+ (setq key-for-key (when id-for-key
+ (canlock-make-cancel-key
+ id-for-key password))
+ key-for-lock (when id-for-lock
+ (canlock-make-cancel-key
+ id-for-lock password)))
+ (if (not (or key-for-key key-for-lock))
+ (message "Couldn't insert Canlock header")
+ (when key-for-key
+ (insert "Cancel-Key: sha1:" key-for-key "\n"))
+ (when key-for-lock
+ (insert "Cancel-Lock: sha1:"
+ (base64-encode-string (funcall canlock-sha1-function
+ key-for-lock))
+ "\n")))))))))
+
+;;;###autoload
+(defun canlock-verify (&optional buffer)
+ "Verify Cancel-Lock or Cancel-Key in BUFFER.
+If BUFFER is nil, the current buffer is assumed. Signal an error if
+it fails. You can modify the behavior of this function to return non-
+nil instead of to signal an error by setting the option
+`canlock-ignore-errors' to non-nil."
+ (interactive)
+ (let ((canlock-sha1-function (or canlock-sha1-function-for-verify
+ canlock-sha1-function))
+ keys locks errmsg id-for-key id-for-lock password
+ key-for-key key-for-lock match)
+ (save-excursion
+ (when buffer
+ (set-buffer buffer))
+ (save-restriction
+ (widen)
+ (canlock-narrow-to-header)
+ (setq keys (canlock-fetch-fields 'key)
+ locks (canlock-fetch-fields))
+ (if (not (or keys locks))
+ (setq errmsg
+ "There are neither Cancel-Lock nor Cancel-Key headers")
+ (setq id-for-key (canlock-fetch-id-for-key)
+ id-for-lock (mail-fetch-field "Message-ID"))
+ (or id-for-key id-for-lock
+ (setq errmsg "There are no Message-ID(s)")))))
+
+ (if errmsg
+ (if canlock-ignore-errors
+ errmsg
+ (error "%s" errmsg))
+
+ (setq password (or canlock-password-for-verify
+ (canlock-read-passwd "Password for Canlock: ")))
+ (if (or (not (stringp password)) (zerop (length password)))
+ (progn
+ (setq errmsg "Password for Canlock is bad")
+ (if canlock-ignore-errors
+ errmsg
+ (error "%s" errmsg)))
+
+ (when keys
+ (when id-for-key
+ (setq key-for-key (canlock-make-cancel-key id-for-key password))
+ (while (and keys (not match))
+ (setq match (string-equal key-for-key (pop keys)))))
+ (setq keys (if match "good" "bad")))
+ (setq match nil)
+
+ (when locks
+ (when id-for-lock
+ (setq key-for-lock
+ (base64-encode-string (funcall canlock-sha1-function
+ (canlock-make-cancel-key
+ id-for-lock password))))
+ (when (and locks (not match))
+ (setq match (string-equal key-for-lock (pop locks)))))
+ (setq locks (if match "good" "bad")))
+
+ (prog1
+ (when (member "bad" (list keys locks))
+ "bad")
+ (cond ((and keys locks)
+ (message "Cancel-Key is %s, Cancel-Lock is %s" keys locks))
+ (locks
+ (message "Cancel-Lock is %s" locks))
+ (keys
+ (message "Cancel-Key is %s" keys))))))))
+
+(provide 'canlock)
+
+;;; canlock.el ends here
(push (or (my-getenv "W3DIR") (expand-file-name "../../w3/lisp/" srcdir))
load-path)
-(push "/usr/share/emacs/site-lisp" load-path)
+;(push "/usr/share/emacs/site-lisp" load-path)
(unless (featurep 'xemacs)
(define-compiler-macro last (&whole form x &optional n)
(setq i (1+ i)
start (1+ start)))
res)))))))))
+
+ (define-compiler-macro copy-list (&whole form list)
+ (if (and (fboundp 'copy-list)
+ (subrp (symbol-function 'copy-list)))
+ form
+ `(let ((list ,list))
+ (if (consp list)
+ (let ((res nil))
+ (while (consp list) (push (pop list) res))
+ (prog1 (nreverse res) (setcdr res list)))
+ (car list)))))
)
;; If we are building w3 in a different directory than the source
(when (featurep 'base64)
(setq files (delete "base64.el" files)))
(condition-case code
- (require 'w3-forms)
+ (require 'w3-parse)
(error
- (message "No w3: %s %s" code (locate-library "w3-forms"))
- (dolist (file '("nnweb.el" "nnlistserv.el" "nnultimate.el"
- "nnslashdot.el" "nnwarchive.el" "webmail.el"
- "nnwfm.el" "nnrss.el"))
+ (message "No w3: %s %s" code (locate-library "w3-parse"))
+ (dolist (file '("nnultimate.el" "webmail.el" "nnwfm.el"))
(setq files (delete file files)))))
+ (condition-case code
+ (require 'mh-e)
+ (error
+ (message "No mh-e: %s %s" code (locate-library "mh-e"))
+ (setq files (delete "gnus-mh.el" files))))
+ (condition-case code
+ (require 'xml)
+ (error
+ (message "No xml: %s %s" code (locate-library "xml"))
+ (setq files (delete "nnrss.el" files))))
(dolist (file
(if (featurep 'xemacs)
'("md5.el" "smiley-ems.el")
- '("gnus-xmas.el" "gnus-picon.el" "messagexmas.el"
- "nnheaderxm.el" "smiley.el")))
+ '("gnus-xmas.el" "messagexmas.el" "nnheaderxm.el" "smiley.el")))
(setq files (delete file files)))
(dolist (file files)
(defun dgnushack-make-auto-load ()
(require 'autoload)
+ (unless (make-autoload '(define-derived-mode child parent name
+ "docstring" body)
+ "file")
+ (defadvice make-autoload (around handle-define-derived-mode activate)
+ "Handle `define-derived-mode'."
+ (if (eq (car-safe (ad-get-arg 0)) 'define-derived-mode)
+ (setq ad-return-value
+ (list 'autoload
+ (list 'quote (nth 1 (ad-get-arg 0)))
+ (ad-get-arg 1)
+ (nth 4 (ad-get-arg 0))
+ t nil))
+ ad-do-it))
+ (put 'define-derived-mode 'doc-string-elt 3))
(let ((generated-autoload-file dgnushack-gnus-load-file)
(make-backup-files nil)
(autoload-package-name "gnus"))
- (if (featurep 'xemacs)
+ (if (featurep 'xemacs)
(if (file-exists-p generated-autoload-file)
(delete-file generated-autoload-file))
(with-temp-file generated-autoload-file
;;; no-byte-compile: t
;;; no-update-autoloads: t
;;; End:
-;;; gnus-load.el ends here\n"))
+;;; gnus-load.el ends here
+")
+ ;; Workaround the bug in some version of XEmacs.
+ (when (featurep 'xemacs)
+ (condition-case nil
+ (require 'cus-load)
+ (error nil))
+ (goto-char (point-min))
+ (when (and (fboundp 'custom-add-loads)
+ (not (search-forward "\n(autoload 'custom-add-loads " nil t)))
+ (search-forward "\n;;; Code:" nil t)
+ (forward-line 1)
+ (insert "\n(autoload 'custom-add-loads \"cus-load\")\n"))))
(message (format "Compiling %s..." dgnushack-gnus-load-file))
(byte-compile-file dgnushack-gnus-load-file))
;;; dig.el --- Domain Name System dig interface
-;; Copyright (c) 2000 Free Software Foundation, Inc.
+;; Copyright (c) 2000, 2001 Free Software Foundation, Inc.
;; Author: Simon Josefsson <simon@josefsson.org>
;; Keywords: DNS BIND dig
;; For use in elisp programs, call `dig-invoke' and use
;; `dig-extract-rr' to extract resource records.
+;;; Release history:
+
+;; 2000-10-28 posted on gnu.emacs.sources
+
;;; Code:
(eval-when-compile (require 'cl))
"Default expressions to highlight in dig mode."
:type 'sexp
:group 'dig)
-
+
(defun dig-invoke (domain &optional
- query-type query-class query-option
+ query-type query-class query-option
dig-option server)
"Call dig with given arguments and return buffer containing output.
DOMAIN is a string with a DNS domain. QUERY-TYPE is an optional string
(save-excursion
(goto-char (point-min))
(if (re-search-forward
- (concat domain "\\.?[\t ]+[0-9wWdDhHmMsS]+[\t ]+"
+ (concat domain "\\.?[\t ]+[0-9wWdDhHmMsS]+[\t ]+"
(upcase (or class "IN")) "[\t ]+" (upcase (or type "A")))
nil t)
(let (b e)
'(dig-font-lock-keywords t)))
(when (featurep 'font-lock)
(font-lock-set-defaults)))
-
+
(defun dig-exit ()
"Quit dig output buffer."
(interactive)
"Query addresses of a DOMAIN using dig, by calling `dig-invoke'.
Optional arguments are passed to `dig-invoke'."
(interactive "sHost: ")
- (switch-to-buffer
+ (switch-to-buffer
(dig-invoke domain query-type query-class query-option dig-option server))
(goto-char (point-min))
(and (search-forward ";; ANSWER SECTION:" nil t)
;;; earcon.el --- Sound effects for messages
-;; Copyright (C) 1996, 2000 Free Software Foundation
+;; Copyright (C) 1996, 2000, 2001 Free Software Foundation
;; Author: Steven L. Baur <steve@miranova.com>
"Turn ** sounds ** into noise."
:group 'gnus-visual)
-(defcustom earcon-auto-play nil
- "*When True, automatically play sounds as well as buttonize them."
- :type 'boolean
- :group 'earcon)
-
(defcustom earcon-prefix "**"
"*String denoting the start of an earcon."
:type 'string
(interactive "e")
(set-buffer (window-buffer (posn-window (event-start event))))
(let* ((pos (posn-point (event-start event)))
- (data (get-text-property pos 'earcon-data))
+ (data (get-text-property pos 'earcon-data))
(fun (get-text-property pos 'earcon-callback)))
(if fun (funcall fun data))))
;;; flow-fill.el --- interprete RFC2646 "flowed" text
-;; Copyright (C) 2000 Free Software Foundation, Inc.
+;; Copyright (C) 2000, 2001 Free Software Foundation, Inc.
;; Author: Simon Josefsson <jas@pdc.kth.se>
;; Keywords: mail
;; Todo: encoding, implement basic `fill-region' (Emacs and XEmacs
;; implementations differ..)
-;; History:
+;;; History:
;; 2000-02-17 posted on ding mailing list
;; 2000-02-19 use `point-at-{b,e}ol' in XEmacs
(unless sig
(let ((fill-prefix (when quote (concat quote " "))))
(fill-region (fill-flowed-point-at-bol)
- (fill-flowed-point-at-eol)
+ (min (1+ (fill-flowed-point-at-eol)) (point-max))
'left 'nosqueeze))))))))
(provide 'flow-fill)
;;; gnus-agent.el --- unplugged support for Gnus
-;; Copyright (C) 1997, 1998, 1999, 2000, 2001
+;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
"Jj" gnus-agent-toggle-plugged
"Js" gnus-agent-fetch-session
"JY" gnus-agent-synchronize-flags
- "JS" gnus-group-send-drafts
+ "JS" gnus-group-send-queue
"Ja" gnus-agent-add-group
"Jr" gnus-agent-remove-group)
'("Agent"
["Toggle plugged" gnus-agent-toggle-plugged t]
["List categories" gnus-enter-category-buffer t]
- ["Send drafts" gnus-group-send-drafts gnus-plugged]
+ ["Send queue" gnus-group-send-queue gnus-plugged]
("Fetch"
["All" gnus-agent-fetch-session gnus-plugged]
["Group" gnus-agent-fetch-group gnus-plugged])))))
(defvar gnus-agent-summary-mode-map (make-sparse-keymap))
(gnus-define-keys gnus-agent-summary-mode-map
"Jj" gnus-agent-toggle-plugged
+ "Ju" gnus-agent-summary-fetch-group
"J#" gnus-agent-mark-article
"J\M-#" gnus-agent-unmark-article
"@" gnus-agent-toggle-mark
["Mark as downloadable" gnus-agent-mark-article t]
["Unmark as downloadable" gnus-agent-unmark-article t]
["Toggle mark" gnus-agent-toggle-mark t]
+ ["Fetch downloadable" gnus-aget-summary-fetch-group t]
["Catchup undownloaded" gnus-agent-catchup t]))))
(defvar gnus-agent-server-mode-map (make-sparse-keymap))
["Add" gnus-agent-add-server t]
["Remove" gnus-agent-remove-server t]))))
+(defun gnus-agent-make-mode-line-string (string mouse-button mouse-func)
+ (if (and (fboundp 'propertize)
+ (fboundp 'make-mode-line-mouse-map))
+ (propertize string 'local-map
+ (make-mode-line-mouse-map mouse-button mouse-func))
+ string))
+
(defun gnus-agent-toggle-plugged (plugged)
"Toggle whether Gnus is unplugged or not."
(interactive (list (not gnus-plugged)))
(setq gnus-plugged plugged)
(gnus-agent-possibly-synchronize-flags)
(gnus-run-hooks 'gnus-agent-plugged-hook)
- (setcar (cdr gnus-agent-mode-status) " Plugged"))
+ (setcar (cdr gnus-agent-mode-status)
+ (gnus-agent-make-mode-line-string " Plugged"
+ 'mouse-2
+ 'gnus-agent-toggle-plugged)))
(gnus-agent-close-connections)
(setq gnus-plugged plugged)
(gnus-run-hooks 'gnus-agent-unplugged-hook)
- (setcar (cdr gnus-agent-mode-status) " Unplugged"))
+ (setcar (cdr gnus-agent-mode-status)
+ (gnus-agent-make-mode-line-string " Unplugged"
+ 'mouse-2
+ 'gnus-agent-toggle-plugged)))
(set-buffer-modified-p t))
(defun gnus-agent-close-connections ()
\(gnus-agentize)
This will modify the `gnus-setup-news-hook', and
-`message-send-mail-function' variables, and install the Gnus agent
+`message-send-mail-real-function' variables, and install the Gnus agent
minor mode in all Gnus buffers."
(interactive)
(gnus-open-agent)
(add-hook 'gnus-setup-news-hook 'gnus-agent-queue-setup)
(unless gnus-agent-send-mail-function
- (setq gnus-agent-send-mail-function message-send-mail-function
- message-send-mail-function 'gnus-agent-send-mail))
+ (setq gnus-agent-send-mail-function (or
+ message-send-mail-real-function
+ message-send-mail-function)
+ message-send-mail-real-function 'gnus-agent-send-mail))
(unless gnus-agent-covered-methods
(setq gnus-agent-covered-methods (list gnus-select-method))))
gcc " ,")))))
covered)
(while (and (not covered) methods)
- (setq covered
- (member (car methods) gnus-agent-covered-methods)
+ (setq covered (gnus-agent-method-p (car methods))
methods (cdr methods)))
covered)))
(defun gnus-agent-fetch-group (group)
"Put all new articles in GROUP into the Agent."
(interactive (list (gnus-group-group-name)))
- (unless gnus-plugged
- (error "Groups can't be fetched when Gnus is unplugged"))
- (unless group
- (error "No group on the current line"))
- (let ((gnus-command-method (gnus-find-method-for-group group)))
- (gnus-agent-with-fetch
- (gnus-agent-fetch-group-1 group gnus-command-method)
- (gnus-message 5 "Fetching %s...done" group))))
+ (let ((state gnus-plugged))
+ (unwind-protect
+ (progn
+ (unless group
+ (error "No group on the current line"))
+ (unless state
+ (gnus-agent-toggle-plugged gnus-plugged))
+ (let ((gnus-command-method (gnus-find-method-for-group group)))
+ (gnus-agent-with-fetch
+ (gnus-agent-fetch-group-1 group gnus-command-method)
+ (gnus-message 5 "Fetching %s...done" group))))
+ (when (and (not state)
+ gnus-plugged)
+ (gnus-agent-toggle-plugged gnus-plugged)))))
(defun gnus-agent-add-group (category arg)
"Add the current group to an agent category."
(unless server
(error "No server on the current line"))
(let ((method (gnus-server-get-method nil (gnus-server-server-name))))
- (when (member method gnus-agent-covered-methods)
+ (when (gnus-agent-method-p method)
(error "Server already in the agent program"))
(push method gnus-agent-covered-methods)
(gnus-server-update-server server)
(unless server
(error "No server on the current line"))
(let ((method (gnus-server-get-method nil (gnus-server-server-name))))
- (unless (member method gnus-agent-covered-methods)
+ (unless (gnus-agent-method-p method)
(error "Server not in the agent program"))
(setq gnus-agent-covered-methods
(delete method gnus-agent-covered-methods))
(pop gnus-newsgroup-undownloaded) gnus-catchup-mark)))
(gnus-summary-position-point))
+(defun gnus-agent-summary-fetch-group ()
+ "Fetch the downloadable articles in the group."
+ (interactive)
+ (let ((articles gnus-newsgroup-downloadable)
+ (gnus-command-method (gnus-find-method-for-group gnus-newsgroup-name))
+ (state gnus-plugged))
+ (unwind-protect
+ (progn
+ (unless state
+ (gnus-agent-toggle-plugged t))
+ (unless articles
+ (error "No articles to download"))
+ (gnus-agent-with-fetch
+ (gnus-agent-fetch-articles gnus-newsgroup-name articles))
+ (save-excursion
+ (dolist (article articles)
+ (setq gnus-newsgroup-downloadable
+ (delq article gnus-newsgroup-downloadable))
+ (gnus-summary-mark-article article gnus-unread-mark))))
+ (when (and (not state)
+ gnus-plugged)
+ (gnus-agent-toggle-plugged nil)))))
+
;;;
;;; Internal functions
;;;
(when (and sym (boundp sym))
(if (and (boundp (setq osym (intern (symbol-name sym) orig)))
(setq elem (symbol-value osym)))
- (setcdr elem (cdr (symbol-value sym)))
+ (progn
+ (if (and (integerp (car (symbol-value sym)))
+ (> (car elem) (car (symbol-value sym))))
+ (setcar elem (car (symbol-value sym))))
+ (if (integerp (cdr (symbol-value sym)))
+ (setcdr elem (cdr (symbol-value sym)))))
(set (intern (symbol-name sym) orig) (symbol-value sym)))))
new))
(gnus-make-directory (file-name-directory file))
(coding-system-for-write nnheader-file-coding-system)
(file-name-coding-system nnmail-pathname-coding-system)
(file (gnus-agent-lib-file "active"))
- oactive)
+ oactive-min)
(gnus-make-directory (file-name-directory file))
(with-temp-file file
;; Emacs got problem to match non-ASCII group in multibyte buffer.
(goto-char (point-min))
(when (re-search-forward
(concat "^" (regexp-quote group) " ") nil t)
- (save-excursion
- (save-restriction
- (narrow-to-region (match-beginning 0)
- (progn
- (forward-line 1)
- (point)))
- (setq oactive (car (nnmail-parse-active)))))
+ (save-excursion
+ (read (current-buffer)) ;; max
+ (setq oactive-min (read (current-buffer)))) ;; min
(gnus-delete-line))
(insert (format "%S %d %d y\n" (intern group)
(cdr active)
- (or (car oactive) (car active))))
+ (or oactive-min (car active))))
(goto-char (point-max))
(while (search-backward "\\." nil t)
(delete-char 1))))))
(file (gnus-agent-article-name ".overview" group)))
;; Add article with marks to list of article headers we want to fetch.
(dolist (arts (gnus-info-marks (gnus-get-info group)))
- (setq articles (gnus-union (gnus-uncompress-sequence (cdr arts))
- articles)))
- (setq articles (sort articles '<))
+ (setq articles (gnus-range-add articles (cdr arts))))
+ (setq articles (sort (gnus-uncompress-sequence articles) '<))
;; Remove known articles.
(when (gnus-agent-load-alist group)
(setq articles (gnus-sorted-intersection
(defun gnus-agent-save-alist (group &optional articles state dir)
"Save the article-state alist for GROUP."
- (let ((file-name-coding-system nnmail-pathname-coding-system))
+ (let ((file-name-coding-system nnmail-pathname-coding-system)
+ print-level print-length)
(with-temp-file (if dir
(expand-file-name ".agentview" dir)
(gnus-agent-article-name ".agentview" group))
(error
(unless (funcall gnus-agent-confirmation-function
(format "Error (%s). Continue? " err))
- (error "Cannot fetch articles into the Gnus agent.")))
+ (error "Cannot fetch articles into the Gnus agent")))
(quit
(unless (funcall gnus-agent-confirmation-function
(format "Quit fetching session (%s). Continue? "
err))
- (signal 'quit "Cannot fetch articles into the Gnus agent."))))
+ (signal 'quit "Cannot fetch articles into the Gnus agent"))))
(pop methods))
(gnus-message 6 "Finished fetching articles into the Gnus agent"))))
(unless (gnus-check-group group)
(error "Can't open server for %s" group))
;; Fetch headers.
- (when (and (or (gnus-active group) (gnus-activate-group group))
+ (when (and (or (gnus-active group)
+ (gnus-activate-group group))
(setq articles (gnus-agent-fetch-headers group))
(let ((nntp-server-buffer gnus-agent-overview-buffer))
;; Parse them and see which articles we want to fetch.
(gnus-get-predicate
(or (gnus-group-find-parameter group 'agent-predicate t)
(cadr category))))
- (if (memq (caaddr predicate) '(gnus-agent-true gnus-agent-false))
+ (if (memq predicate '(gnus-agent-true gnus-agent-false))
;; Simple implementation
- (setq arts
- (and (eq (caaddr predicate) 'gnus-agent-true) articles))
+ (setq arts (and (eq predicate 'gnus-agent-true) articles))
(setq arts nil)
(setq score-param
(or (gnus-group-get-parameter group 'agent-score t)
(setq arts (assq 'download (gnus-info-marks
(setq info (gnus-get-info group)))))
(when (cdr arts)
+ (gnus-message 8 "Agent is downloading marked articles...")
(gnus-agent-fetch-articles
group (gnus-uncompress-range (cdr arts)))
(setq marks (delq arts (gnus-info-marks info)))
(defalias 'gnus-category-position-point 'gnus-goto-colon)
(defun gnus-category-insert-line (category)
- (let* ((gnus-tmp-name (car category))
+ (let* ((gnus-tmp-name (format "%s" (car category)))
(gnus-tmp-groups (length (cadddr category))))
(beginning-of-line)
(gnus-add-text-properties
(defun gnus-category-make-function (cat)
"Make a function from category CAT."
- `(lambda () ,(gnus-category-make-function-1 cat)))
+ (let ((func (gnus-category-make-function-1 cat)))
+ (if (and (= (length func) 1)
+ (symbolp (car func)))
+ (car func)
+ (gnus-byte-compile `(lambda () ,func)))))
(defun gnus-agent-true ()
"Return t."
(let ((init-file-user "")
(gnus-always-read-dribble-file t))
(gnus))
- (gnus-group-send-drafts)
+ (gnus-group-send-queue)
(gnus-agent-fetch-session))
(provide 'gnus-agent)
;;; gnus-art.el --- article mode commands for Gnus
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
(require 'gnus-sum)
(require 'gnus-spec)
(require 'gnus-int)
+(require 'gnus-win)
(require 'mm-bodies)
(require 'mail-parse)
(require 'mm-decode)
"^X-Received:" "^Content-length:" "X-precedence:"
"^X-Authenticated-User:" "^X-Comment" "^X-Report:" "^X-Abuse-Info:"
"^X-HTTP-Proxy:" "^X-Mydeja-Info:" "^X-Copyright" "^X-No-Markup:"
- "^X-Abuse-Info:")
+ "^X-Abuse-Info:" "^X-From_:" "^X-Accept-Language:" "^Errors-To:"
+ "^X-BeenThere:" "^X-Mailman-Version:" "^List-Help:" "^List-Post:"
+ "^List-Subscribe:" "^List-Id:" "^List-Unsubscribe:" "^List-Archive:"
+ "^X-Content-length:" "^X-Posting-Agent:" "^Original-Received:"
+ "^X-Request-PGP:" "^X-Fingerprint:" "^X-WRIEnvto:" "^X-WRIEnvfrom:"
+ "^X-Virus-Scanned:" "^X-Delivery-Agent:" "^Posted-Date:" "^X-Gateway:"
+ "^X-Local-Origin:" "^X-Local-Destination:" "^X-UserInfo1:")
"*All headers that start with this regexp will be hidden.
This variable can also be a list of regexps of headers to be ignored.
If `gnus-visible-headers' is non-nil, this variable will be ignored."
(defcustom gnus-boring-article-headers '(empty followup-to reply-to)
"Headers that are only to be displayed if they have interesting data.
-Possible values in this list are `empty', `newsgroups', `followup-to',
-`to-address', `reply-to', `date', `long-to', and `many-to'."
+Possible values in this list are:
+
+ 'empty Headers with no content.
+ 'newsgroups Newsgroup identical to Gnus group.
+ 'to-address To identical to To-address.
+ 'followup-to Followup-to identical to Newsgroups.
+ 'reply-to Reply-to identical to From.
+ 'date Date less than four days old.
+ 'long-to To and/or Cc longer than 1024 characters.
+ 'many-to Multiple To and/or Cc."
:type '(set (const :tag "Headers with no content." empty)
- (const :tag "Newsgroups with only one group." newsgroups)
- (const :tag "To identical to to-address." to-address)
- (const :tag "Followup-to identical to newsgroups." followup-to)
- (const :tag "Reply-to identical to from." reply-to)
+ (const :tag "Newsgroups identical to Gnus group." newsgroups)
+ (const :tag "To identical to To-address." to-address)
+ (const :tag "Followup-to identical to Newsgroups." followup-to)
+ (const :tag "Reply-to identical to From." reply-to)
(const :tag "Date less than four days old." date)
- (const :tag "Very long To and/or Cc header." long-to)
+ (const :tag "To and/or Cc longer than 1024 characters." long-to)
(const :tag "Multiple To and/or Cc headers." many-to))
:group 'gnus-article-hiding)
;; Fixme: This isn't the right thing for mixed graphical and and
;; non-graphical frames in a session.
-;; gnus-xmas.el overrides this for XEmacs.
(defcustom gnus-article-x-face-command
- (if (and (fboundp 'image-type-available-p)
- (image-type-available-p 'xbm))
- 'gnus-article-display-xface
- (if gnus-article-compface-xbm
- "{ echo '/* Width=48, Height=48 */'; uncompface; } | display -"
- "{ echo '/* Width=48, Height=48 */'; uncompface; } | icontopbm | \
-display -"))
+ (if (featurep 'xemacs)
+ (if (or (gnus-image-type-available-p 'xface)
+ (gnus-image-type-available-p 'xpm))
+ 'gnus-xmas-article-display-xface
+ "{ echo '/* Width=48, Height=48 */'; uncompface; } | icontopbm | ee -")
+ (if (gnus-image-type-available-p 'xbm)
+ 'gnus-article-display-xface
+ (if gnus-article-compface-xbm
+ "{ echo '/* Width=48, Height=48 */'; uncompface; } | display -"
+ "{ echo '/* Width=48, Height=48 */'; uncompface; } | icontopbm | \
+display -")))
"*String or function to be executed to display an X-Face header.
If it is a string, the command will be executed in a sub-shell
asynchronously. The compressed face will be piped to this command."
- :type '(choice string
- (function-item gnus-article-display-xface)
+ :type `(choice string
+ (function-item
+ ,(if (featurep 'xemacs)
+ 'gnus-xmas-article-display-xface
+ 'gnus-article-display-xface))
function)
:version "21.1"
:group 'gnus-article-washing)
* gnus-summary-save-in-mail (Unix mail format)
* gnus-summary-save-in-folder (MH folder)
* gnus-summary-save-in-file (article format)
+* gnus-summary-save-body-in-file (article body)
* gnus-summary-save-in-vm (use VM's folder format)
* gnus-summary-write-to-file (article format -- overwrite)."
:group 'gnus-article-saving
(function-item gnus-summary-save-in-mail)
(function-item gnus-summary-save-in-folder)
(function-item gnus-summary-save-in-file)
+ (function-item gnus-summary-save-body-in-file)
(function-item gnus-summary-save-in-vm)
(function-item gnus-summary-write-to-file)))
(face :value default)))))
(defcustom gnus-article-decode-hook
- '(article-decode-charset article-decode-encoded-words)
+ '(article-decode-charset article-decode-encoded-words
+ article-decode-group-name)
"*Hook run to decode charsets in articles."
:group 'gnus-article-headers
:type 'hook)
:type '(repeat regexp))
(defcustom gnus-unbuttonized-mime-types '(".*/.*")
- "List of MIME types that should not be given buttons when rendered inline."
+ "List of MIME types that should not be given buttons when rendered inline.
+See also `gnus-buttonized-mime-types' which may override this variable."
+ :version "21.1"
+ :group 'gnus-article-mime
+ :type '(repeat regexp))
+
+(defcustom gnus-buttonized-mime-types nil
+ "List of MIME types that should be given buttons when rendered inline.
+If set, this variable overrides `gnus-unbuttonized-mime-types'.
+To see e.g. security buttons you could set this to
+`(\"multipart/signed\")'."
:version "21.1"
:group 'gnus-article-mime
:type '(repeat regexp))
(defcustom gnus-treat-highlight-signature '(or last (typep "text/x-vcard"))
"Highlight the signature.
Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles'."
:group 'gnus-article-treat
:type gnus-article-treat-custom)
(put 'gnus-treat-highlight-signature 'highlight t)
:group 'gnus-article-treat
:type gnus-article-treat-custom)
-(defcustom gnus-treat-hide-citation-maybe nil
- "Hide cited text.
-Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
- :group 'gnus-article-treat
- :type gnus-article-treat-custom)
-
(defcustom gnus-treat-strip-list-identifiers 'head
"Strip list identifiers from `gnus-list-identifiers`.
Valid values are nil, t, `head', `last', an integer or a predicate.
:group 'gnus-article-treat
:type gnus-article-treat-custom)
+(defcustom gnus-treat-unfold-headers 'head
+ "Unfold folded header lines.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+ :group 'gnus-article-treat
+ :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-fold-newsgroups 'head
+ "Fold the Newsgroups and Followup-To headers.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+ :group 'gnus-article-treat
+ :type gnus-article-treat-custom)
+
(defcustom gnus-treat-overstrike t
"Treat overstrike highlighting.
Valid values are nil, t, `head', `last', an integer or a predicate.
(and (or (and (fboundp 'image-type-available-p)
(image-type-available-p 'xbm)
(string-match "^0x" (shell-command-to-string "uncompface")))
- (and (featurep 'xemacs) (featurep 'xface)))
+ (and (featurep 'xemacs)
+ (featurep 'xface)))
'head)
"Display X-Face headers.
Valid values are nil, t, `head', `last', an integer or a predicate.
:type gnus-article-treat-custom)
(put 'gnus-treat-display-smileys 'highlight t)
-(defcustom gnus-treat-display-picons (if (featurep 'xemacs) 'head nil)
- "Display picons.
+(defcustom gnus-treat-from-picon
+ (if (gnus-image-type-available-p 'xpm)
+ 'head nil)
+ "Display picons in the From header.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+ :group 'gnus-article-treat
+ :type gnus-article-treat-head-custom)
+(put 'gnus-treat-from-picon 'highlight t)
+
+(defcustom gnus-treat-mail-picon
+ (if (gnus-image-type-available-p 'xpm)
+ 'head nil)
+ "Display picons in To and Cc headers.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+ :group 'gnus-article-treat
+ :type gnus-article-treat-head-custom)
+(put 'gnus-treat-mail-picon 'highlight t)
+
+(defcustom gnus-treat-newsgroups-picon
+ (if (gnus-image-type-available-p 'xpm)
+ 'head nil)
+ "Display picons in the Newsgroups and Followup-To headers.
Valid values are nil, t, `head', `last', an integer or a predicate.
See the manual for details."
:group 'gnus-article-treat
:type gnus-article-treat-head-custom)
-(put 'gnus-treat-display-picons 'highlight t)
+(put 'gnus-treat-newsgroups-picon 'highlight t)
+
+(defcustom gnus-treat-body-boundary
+ (if (or gnus-treat-newsgroups-picon
+ gnus-treat-mail-picon
+ gnus-treat-from-picon)
+ 'head nil)
+ "Draw a boundary at the end of the headers.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See the manual for details."
+ :version "21.1"
+ :group 'gnus-article-treat
+ :type gnus-article-treat-custom)
(defcustom gnus-treat-capitalize-sentences nil
"Capitalize sentence-starting words.
(defvar article-goto-body-goes-to-point-min-p nil)
(defvar gnus-article-wash-types nil)
(defvar gnus-article-emphasis-alist nil)
+(defvar gnus-article-image-alist nil)
(defvar gnus-article-mime-handle-alist-1 nil)
(defvar gnus-treatment-function-alist
(gnus-treat-fill-article gnus-article-fill-cited-article)
(gnus-treat-fill-long-lines gnus-article-fill-long-lines)
(gnus-treat-strip-cr gnus-article-remove-cr)
- (gnus-treat-emphasize gnus-article-emphasize)
- (gnus-treat-display-xface gnus-article-display-x-face)
(gnus-treat-date-ut gnus-article-date-ut)
(gnus-treat-date-local gnus-article-date-local)
(gnus-treat-date-english gnus-article-date-english)
(gnus-treat-leading-whitespace gnus-article-remove-leading-whitespace)
(gnus-treat-strip-pgp gnus-article-hide-pgp)
(gnus-treat-strip-pem gnus-article-hide-pem)
+ (gnus-treat-from-picon gnus-treat-from-picon)
+ (gnus-treat-mail-picon gnus-treat-mail-picon)
+ (gnus-treat-newsgroups-picon gnus-treat-newsgroups-picon)
(gnus-treat-highlight-headers gnus-article-highlight-headers)
(gnus-treat-highlight-citation gnus-article-highlight-citation)
(gnus-treat-highlight-signature gnus-article-highlight-signature)
(gnus-treat-strip-multiple-blank-lines
gnus-article-strip-multiple-blank-lines)
(gnus-treat-overstrike gnus-article-treat-overstrike)
+ (gnus-treat-unfold-headers gnus-article-treat-unfold-headers)
+ (gnus-treat-fold-newsgroups gnus-article-treat-fold-newsgroups)
(gnus-treat-buttonize-head gnus-article-add-buttons-to-head)
(gnus-treat-display-smileys gnus-smiley-display)
(gnus-treat-capitalize-sentences gnus-article-capitalize-sentences)
- (gnus-treat-display-picons gnus-article-display-picons)
+ (gnus-treat-emphasize gnus-article-emphasize)
+ (gnus-treat-display-xface gnus-article-display-x-face)
+ (gnus-treat-body-boundary gnus-article-treat-body-boundary)
(gnus-treat-play-sounds gnus-earcon-display)))
(defvar gnus-article-mime-handle-alist nil)
(defvar gnus-inhibit-hiding nil)
+;;; Macros for dealing with the article buffer.
+
+(defmacro gnus-with-article-headers (&rest forms)
+ `(save-excursion
+ (set-buffer gnus-article-buffer)
+ (save-restriction
+ (let ((buffer-read-only nil)
+ (inhibit-point-motion-hooks t)
+ (case-fold-search t))
+ (article-narrow-to-head)
+ ,@forms))))
+
+(put 'gnus-with-article-headers 'lisp-indent-function 0)
+(put 'gnus-with-article-headers 'edebug-form-spec '(body))
+
+(defmacro gnus-with-article-buffer (&rest forms)
+ `(save-excursion
+ (set-buffer gnus-article-buffer)
+ (let ((buffer-read-only nil))
+ ,@forms)))
+
+(put 'gnus-with-article-buffer 'lisp-indent-function 0)
+(put 'gnus-with-article-buffer 'edebug-form-spec '(body))
+
+(defun gnus-article-goto-header (header)
+ "Go to HEADER, which is a regular expression."
+ (re-search-forward (concat "^\\(" header "\\):") nil t))
+
(defsubst gnus-article-hide-text (b e props)
"Set text PROPS on the B to E region, extending `intangible' 1 past B."
(gnus-add-text-properties-when 'article-type nil b e props)
(defun gnus-article-hide-text-type (b e type)
"Hide text of TYPE between B and E."
- (push type gnus-article-wash-types)
+ (gnus-add-wash-type type)
(gnus-article-hide-text
b e (cons 'article-type (cons type gnus-hidden-properties))))
(defun gnus-article-unhide-text-type (b e type)
"Unhide text of TYPE between B and E."
- (setq gnus-article-wash-types
- (delq type gnus-article-wash-types))
+ (gnus-delete-wash-type type)
(remove-text-properties
b e (cons 'article-type (cons type gnus-hidden-properties)))
(when (memq 'intangible gnus-hidden-properties)
;; `gnus-ignored-headers' and `gnus-visible-headers' to
;; select which header lines is to remain visible in the
;; article buffer.
- (while (re-search-forward "^[^ \t]*:" nil t)
+ (while (re-search-forward "^[^ \t:]*:" nil t)
(beginning-of-line)
;; Mark the rank of the header.
(put-text-property
(when (setq beg (text-property-any
(point-min) (point-max) 'message-rank (+ 2 max)))
;; We delete the unwanted headers.
- (push 'headers gnus-article-wash-types)
+ (gnus-add-wash-type 'headers)
(add-text-properties (point-min) (+ 5 (point-min))
'(article-type headers dummy-invisible t))
(delete-region beg (point-max))))))))
(put-text-property
(point) (1+ (point)) 'face 'underline)))))))))
+(defun gnus-article-treat-unfold-headers ()
+ "Unfold folded message headers.
+Only the headers that fit into the current window width will be
+unfolded."
+ (interactive)
+ (gnus-with-article-headers
+ (let (length)
+ (while (not (eobp))
+ (save-restriction
+ (mail-header-narrow-to-field)
+ (let ((header (buffer-substring (point-min) (point-max))))
+ (with-temp-buffer
+ (insert header)
+ (goto-char (point-min))
+ (while (re-search-forward "[\t ]*\n[\t ]+" nil t)
+ (replace-match " " t t)))
+ (setq length (- (point-max) (point-min) 1)))
+ (when (< length (window-width))
+ (while (re-search-forward "[\t ]*\n[\t ]+" nil t)
+ (replace-match " " t t)))
+ (goto-char (point-max)))))))
+
+(defun gnus-article-treat-fold-newsgroups ()
+ "Unfold folded message headers.
+Only the headers that fit into the current window width will be
+unfolded."
+ (interactive)
+ (gnus-with-article-headers
+ (while (gnus-article-goto-header "newsgroups\\|followup-to")
+ (save-restriction
+ (mail-header-narrow-to-field)
+ (while (search-forward "," nil t)
+ (replace-match ", " t t))
+ (mail-header-fold-field)
+ (goto-char (point-max))))))
+
+(defun gnus-article-treat-body-boundary ()
+ "Place a boundary line at the end of the headers."
+ (interactive)
+ (gnus-with-article-headers
+ (goto-char (point-max))
+ (let ((start (point)))
+ (insert "X-Boundary: ")
+ (gnus-add-text-properties start (point) '(invisible t intangible t))
+ (insert (make-string (1- (window-width)) ?-)
+ "\n"))))
+
(defun article-fill-long-lines ()
"Fill lines that are wider than the window width."
(interactive)
(width (window-width (get-buffer-window (current-buffer)))))
(save-restriction
(article-goto-body)
- (let ((adaptive-fill-mode nil))
+ (let ((adaptive-fill-mode nil)) ;Why? -sm
(while (not (eobp))
(end-of-line)
(when (>= (current-column) (min fill-column width))
(defun article-display-x-face (&optional force)
"Look for an X-Face header and display it if present."
(interactive (list 'force))
- (save-excursion
+ (gnus-with-article-headers
;; Delete the old process, if any.
(when (process-status "article-x-face")
(delete-process "article-x-face"))
- (let ((inhibit-point-motion-hooks t)
- x-faces
- (case-fold-search t)
- from last)
- (save-restriction
- (article-narrow-to-head)
- (when (and buffer-read-only ;; When type `W f'
- (progn
- (goto-char (point-min))
- (not (re-search-forward "^X-Face:[\t ]*" nil t)))
- (gnus-buffer-live-p gnus-original-article-buffer))
- (with-current-buffer gnus-original-article-buffer
- (save-restriction
- (article-narrow-to-head)
- (while (re-search-forward "^X-Face:" nil t)
- (setq x-faces
- (concat
- (or x-faces "")
- (buffer-substring
- (match-beginning 0)
- (1- (re-search-forward
- "^\\($\\|[^ \t]\\)" nil t))))))))
- (if x-faces
- (let (point start bface eface buffer-read-only)
- (goto-char (point-max))
- (forward-line -1)
- (setq bface (get-text-property (gnus-point-at-bol) 'face)
- eface (get-text-property (1- (gnus-point-at-eol)) 'face))
- (goto-char (point-max))
- (setq point (point))
- (insert x-faces)
- (goto-char point)
- (while (looking-at "\\([^:]+\\): *")
- (put-text-property (match-beginning 1) (1+ (match-end 1))
- 'face bface)
- (setq start (match-end 0))
- (forward-line 1)
- (while (looking-at "[\t ]")
- (forward-line 1))
- (put-text-property start (point)
- 'face eface)))))
- (goto-char (point-min))
- (setq from (message-fetch-field "from"))
- (goto-char (point-min))
- (while (and gnus-article-x-face-command
- (not last)
+ (if (memq 'xface gnus-article-wash-types)
+ ;; We have already displayed X-Faces, so we remove them
+ ;; instead.
+ (gnus-delete-images 'xface)
+ ;; Display X-Faces.
+ (let (x-faces from face)
+ (save-excursion
+ (set-buffer gnus-original-article-buffer)
+ (save-restriction
+ (mail-narrow-to-head)
+ (while (gnus-article-goto-header "x-face")
+ (push (mail-header-field-value) x-faces))
+ (setq from (message-fetch-field "from"))))
+ ;; Sending multiple EOFs to xv doesn't work, so we only do a
+ ;; single external face.
+ (when (stringp gnus-article-x-face-command)
+ (setq x-faces (list (car x-faces))))
+ (while (and (setq face (pop x-faces))
+ gnus-article-x-face-command
(or force
;; Check whether this face is censored.
(not gnus-article-x-face-too-ugly)
(and gnus-article-x-face-too-ugly from
(not (string-match gnus-article-x-face-too-ugly
- from))))
- ;; Has to be present.
- (re-search-forward "^X-Face:[\t ]*" nil t))
- ;; This used to try to do multiple faces (`while' instead of
- ;; `when' above), but (a) sending multiple EOFs to xv doesn't
- ;; work (b) it can crash some versions of Emacs (c) are
- ;; multiple faces really something to encourage?
- (when (stringp gnus-article-x-face-command)
- (setq last t))
- ;; We now have the area of the buffer where the X-Face is stored.
- (save-excursion
- (let ((beg (point))
- (end (1- (re-search-forward "^\\($\\|[^ \t]\\)" nil t))))
- ;; We display the face.
- (if (symbolp gnus-article-x-face-command)
- ;; The command is a lisp function, so we call it.
- (if (gnus-functionp gnus-article-x-face-command)
- (funcall gnus-article-x-face-command beg end)
- (error "%s is not a function" gnus-article-x-face-command))
- ;; The command is a string, so we interpret the command
- ;; as a, well, command, and fork it off.
- (let ((process-connection-type nil))
- (process-kill-without-query
- (start-process
- "article-x-face" nil shell-file-name shell-command-switch
- gnus-article-x-face-command))
- (process-send-region "article-x-face" beg end)
- (process-send-eof "article-x-face"))))))))))
+ from)))))
+ ;; We display the face.
+ (if (symbolp gnus-article-x-face-command)
+ ;; The command is a lisp function, so we call it.
+ (if (gnus-functionp gnus-article-x-face-command)
+ (funcall gnus-article-x-face-command face)
+ (error "%s is not a function" gnus-article-x-face-command))
+ ;; The command is a string, so we interpret the command
+ ;; as a, well, command, and fork it off.
+ (let ((process-connection-type nil))
+ (process-kill-without-query
+ (start-process
+ "article-x-face" nil shell-file-name shell-command-switch
+ gnus-article-x-face-command))
+ (with-temp-buffer
+ (insert face)
+ (process-send-region "article-x-face" (point-min) (point-max)))
+ (process-send-eof "article-x-face"))))))))
(defun article-decode-mime-words ()
"Decode all MIME-encoded words in the article."
(article-narrow-to-head)
(funcall gnus-decode-header-function (point-min) (point-max)))))
-(defun article-de-quoted-unreadable (&optional force)
+(defun article-decode-group-name ()
+ "Decode group names in `Newsgroups:'."
+ (let ((inhibit-point-motion-hooks t)
+ buffer-read-only
+ (method (gnus-find-method-for-group gnus-newsgroup-name)))
+ (when (and (or gnus-group-name-charset-method-alist
+ gnus-group-name-charset-group-alist)
+ (gnus-buffer-live-p gnus-original-article-buffer))
+ (when (nnmail-fetch-field "Newsgroups")
+ (nnheader-replace-header "Newsgroups"
+ (gnus-decode-newsgroups
+ (with-current-buffer
+ gnus-original-article-buffer
+ (nnmail-fetch-field "Newsgroups"))
+ gnus-newsgroup-name method)))
+ (when (nnmail-fetch-field "Followup-To")
+ (nnheader-replace-header "Followup-To"
+ (gnus-decode-newsgroups
+ (with-current-buffer
+ gnus-original-article-buffer
+ (nnmail-fetch-field "Followup-To"))
+ gnus-newsgroup-name method))))))
+
+(defun article-de-quoted-unreadable (&optional force read-charset)
"Translate a quoted-printable-encoded article.
If FORCE, decode the article whether it is marked as quoted-printable
-or not."
- (interactive (list 'force))
+or not.
+If READ-CHARSET, ask for a coding system."
+ (interactive (list 'force current-prefix-arg))
(save-excursion
(let ((buffer-read-only nil) type charset)
(if (gnus-buffer-live-p gnus-original-article-buffer)
(mail-content-type-get ctl 'charset)))
(if (stringp charset)
(setq charset (intern (downcase charset)))))))
+ (if read-charset
+ (setq charset (mm-read-coding-system "Charset: " charset)))
(unless charset
(setq charset gnus-newsgroup-charset))
(when (or force
(quoted-printable-decode-region
(point) (point-max) (mm-charset-to-coding-system charset))))))
-(defun article-de-base64-unreadable (&optional force)
+(defun article-de-base64-unreadable (&optional force read-charset)
"Translate a base64 article.
-If FORCE, decode the article whether it is marked as base64 not."
- (interactive (list 'force))
+If FORCE, decode the article whether it is marked as base64 not.
+If READ-CHARSET, ask for a coding system."
+ (interactive (list 'force current-prefix-arg))
(save-excursion
(let ((buffer-read-only nil) type charset)
(if (gnus-buffer-live-p gnus-original-article-buffer)
(mail-content-type-get ctl 'charset)))
(if (stringp charset)
(setq charset (intern (downcase charset)))))))
+ (if read-charset
+ (setq charset (mm-read-coding-system "Charset: " charset)))
(unless charset
(setq charset gnus-newsgroup-charset))
(when (or force
(let ((buffer-read-only nil))
(rfc1843-decode-region (point-min) (point-max)))))
-(defun article-wash-html ()
- "Format an html article."
- (interactive)
+(defun article-wash-html (&optional read-charset)
+ "Format an html article.
+If READ-CHARSET, ask for a coding system."
+ (interactive "P")
(save-excursion
(let ((buffer-read-only nil)
charset)
(mail-content-type-get ctl 'charset)))
(if (stringp charset)
(setq charset (intern (downcase charset)))))))
+ (if read-charset
+ (setq charset (mm-read-coding-system "Charset: " charset)))
(unless charset
(setq charset gnus-newsgroup-charset))
(article-goto-body)
(narrow-to-region (point) (point-max))
(mm-setup-w3)
(let ((w3-strict-width (window-width))
- (url-standalone-mode t))
+ (url-standalone-mode t)
+ (w3-honor-stylesheets nil)
+ (w3-delay-image-loads t))
(condition-case var
(w3-region (point-min) (point-max))
(error))))))))
(article-goto-body)
;; Hide the "header".
(when (re-search-forward "^-----BEGIN PGP SIGNED MESSAGE-----\n" nil t)
- (push 'pgp gnus-article-wash-types)
+ (gnus-add-wash-type 'pgp)
(delete-region (match-beginning 0) (match-end 0))
;; Remove armor headers (rfc2440 6.2)
(delete-region (point) (or (re-search-forward "^[ \t]*\n" nil t)
"\n-----BEGIN PRIVACY-ENHANCED MESSAGE-----\n"
nil t)
(setq end (1+ (match-beginning 0))))
- (push 'pem gnus-article-wash-types)
+ (gnus-add-wash-type 'pem)
(gnus-article-hide-text-type
end
(if (search-forward "\n\n" nil t)
(start (point))
(end (point-max))
(orig (buffer-substring start end))
- (trans (babel-as-string orig)))
+ (trans (babel-as-string orig)))
(save-restriction
(narrow-to-region start end)
(delete-region start end)
- (insert trans))))))
+ (insert trans))))))
(defun article-hide-signature (&optional arg)
"Hide the signature in the current article.
(let ((buffer-read-only nil))
(when (gnus-article-narrow-to-signature)
(gnus-article-hide-text-type
- (point-min) (point-max) 'signature)))))))
+ (point-min) (point-max) 'signature))))))
+ (gnus-set-mode-line 'article))
(defun article-strip-headers-in-body ()
"Strip offensive headers from bodies."
(replace-match "" nil t)))
;; Then replace multiple empty lines with a single empty line.
(article-goto-body)
- (while (re-search-forward "\n\n\n+" nil t)
+ (while (re-search-forward "\n\n\\(\n+\\)" nil t)
(unless (gnus-annotation-in-region-p
(match-beginning 0) (match-end 0))
- (replace-match "\n\n" t t))))))
+ (delete-region (match-beginning 1) (match-end 1)))))))
(defun article-strip-leading-space ()
"Remove all white space from the beginning of the lines in the article."
(defun gnus-article-check-hidden-text (type arg)
"Return nil if hiding is necessary.
-Arg can be nil or a number. Nil and positive means hide, negative
+Arg can be nil or a number. nil and positive means hide, negative
means show, 0 means toggle."
(save-excursion
(save-restriction
'article-type type
(point-min) (point-max)
(cons 'article-type (cons type
- gnus-hidden-properties)))))
+ gnus-hidden-properties)))
+ (gnus-delete-wash-type type)))
(defconst article-time-units
`((year . ,(* 365.25 24 60 60))
(message-fetch-field "date")
""))
(tdate-regexp "^Date:[ \t]\\|^X-Sent:[ \t]")
- (date-regexp
+ (date-regexp
(cond
((not gnus-article-date-lapsed-new-header)
tdate-regexp)
(when (and date (not (string= date "")))
(goto-char (point-min))
(let ((buffer-read-only nil))
- ;; Delete any old Date headers.
- (while (re-search-forward date-regexp nil t)
+ ;; Delete any old Date headers.
+ (while (re-search-forward date-regexp nil t)
(if pos
(delete-region (progn (beginning-of-line) (point))
(progn (forward-line 1) (point)))
(condition-case ()
(let ((time (date-to-time date)))
(cond
- ;; Convert to the local timezone.
+ ;; Convert to the local timezone.
((eq type 'local)
(let ((tz (car (current-time-zone time))))
(format "Date: %s %s%02d%02d" (current-time-string time)
visible (nth 2 elem)
face (nth 3 elem))
(while (re-search-forward regexp nil t)
- (when (and (match-beginning visible) (match-beginning invisible))
- (push 'emphasis gnus-article-wash-types)
- (gnus-article-hide-text
- (match-beginning invisible) (match-end invisible) props)
- (gnus-article-unhide-text-type
- (match-beginning visible) (match-end visible) 'emphasis)
- (gnus-put-text-property-excluding-newlines
- (match-beginning visible) (match-end visible) 'face face)
- (goto-char (match-end invisible)))))))))
+ (when (and (match-beginning visible) (match-beginning invisible))
+ (gnus-article-hide-text
+ (match-beginning invisible) (match-end invisible) props)
+ (gnus-article-unhide-text-type
+ (match-beginning visible) (match-end visible) 'emphasis)
+ (gnus-put-overlay-excluding-newlines
+ (match-beginning visible) (match-end visible) 'face face)
+ (gnus-add-wash-type 'emphasis)
+ (goto-char (match-end invisible)))))))))
(defun gnus-article-setup-highlight-words (&optional highlight-words)
"Setup newsgroup emphasis alist."
filename)
(defun gnus-summary-write-to-file (&optional filename)
- "Write this article to a file.
+ "Write this article to a file, overwriting it if the file exists.
Optional argument FILENAME specifies file name.
The directory to save in defaults to `gnus-article-save-directory'."
(gnus-summary-save-in-file nil t))
(when (string-equal command "")
(if gnus-last-shell-command
(setq command gnus-last-shell-command)
- (error "A command is required.")))
+ (error "A command is required")))
(gnus-eval-in-buffer-window gnus-article-buffer
(save-restriction
(widen)
(shell-command-on-region (point-min) (point-max) command nil)))
(setq gnus-last-shell-command command))
+(defun gnus-summary-pipe-to-muttprint (&optional command)
+ "Pipe this article to muttprint."
+ (setq command (read-string
+ "Print using command: " gnus-summary-muttprint-program
+ nil gnus-summary-muttprint-program))
+ (gnus-summary-save-in-pipe command))
+
;;; Article file names when saving.
(defun gnus-capitalize-newsgroup (newsgroup)
(expand-file-name
(if (gnus-use-long-file-name 'not-save)
newsgroup
- (expand-file-name "news" (gnus-newsgroup-directory-form newsgroup)))
+ (file-relative-name
+ (expand-file-name "news" (gnus-newsgroup-directory-form newsgroup))
+ default-directory))
gnus-article-save-directory)))
(defun gnus-sender-save-name (newsgroup headers &optional last-file)
(put-text-property (match-end 0) (point-max)
'face eface)))))))))
+(defun article-verify-cancel-lock ()
+ "Verify Cancel-Lock header."
+ (interactive)
+ (if (gnus-buffer-live-p gnus-original-article-buffer)
+ (canlock-verify gnus-original-article-buffer)))
+
(eval-and-compile
(mapcar
(lambda (func)
(setq afunc func
gfunc (intern (format "gnus-%s" func))))
(defalias gfunc
- (if (fboundp afunc)
+ (when (fboundp afunc)
`(lambda (&optional interactive &rest args)
,(documentation afunc t)
(interactive (list t))
(apply ',afunc args))))))))
'(article-hide-headers
article-verify-x-pgp-sig
+ article-verify-cancel-lock
article-hide-boring-headers
article-treat-overstrike
article-fill-long-lines
;; Note "Commands" menu is defined in gnus-sum.el for consistency
;; Note "Post" menu is defined in gnus-sum.el for consistency
-
+
(gnus-run-hooks 'gnus-article-menu-hook)))
;; Fixme: do something for the Emacs tool bar in Article mode a la
(make-local-variable 'gnus-article-decoded-p)
(make-local-variable 'gnus-article-mime-handle-alist)
(make-local-variable 'gnus-article-wash-types)
+ (make-local-variable 'gnus-article-image-alist)
(make-local-variable 'gnus-article-charset)
(make-local-variable 'gnus-article-ignored-charsets)
(gnus-set-default-directory)
;; from the head of the article.
(defun gnus-article-set-window-start (&optional line)
(set-window-start
- (get-buffer-window gnus-article-buffer t)
+ (gnus-get-buffer-window gnus-article-buffer t)
(save-excursion
(set-buffer gnus-article-buffer)
(goto-char (point-min))
(unless (eq major-mode 'gnus-article-mode)
(gnus-article-mode))
(setq buffer-read-only nil
- gnus-article-wash-types nil)
+ gnus-article-wash-types nil
+ gnus-article-image-alist nil)
(gnus-run-hooks 'gnus-tmp-internal-hook)
(when gnus-display-mime-function
(funcall gnus-display-mime-function))
(gnus-mime-inline-part "i" "View As Text, In This Buffer")
(gnus-mime-internalize-part "E" "View Internally")
(gnus-mime-externalize-part "e" "View Externally")
+ (gnus-mime-print-part "p" "Print")
(gnus-mime-pipe-part "|" "Pipe To Command...")
(gnus-mime-action-on-part "." "Take action on the part")))
(goto-char (point-min))
(or (search-forward "\n\n") (goto-char (point-max)))
(let (buffer-read-only)
- (delete-region (point) (point-max)))
- (mm-display-parts handles)))))
+ (delete-region (point) (point-max))
+ (mm-display-parts handles))))))
(defun gnus-mime-save-part-and-strip ()
"Save the MIME part under point then replace it with an external body."
(interactive)
(gnus-article-check-buffer)
(let* ((data (get-text-property (point) 'gnus-data))
- file param)
+ file param
+ (handles gnus-article-mime-handles))
(if (mm-multiple-handles gnus-article-mime-handles)
- (error "This function is not implemented."))
+ (error "This function is not implemented"))
(setq file (and data (mm-save-part data)))
(when file
(with-current-buffer (mm-handle-buffer data)
(mbl mml-buffer-list))
(setq mml-buffer-list nil)
(insert-buffer gnus-original-article-buffer)
- (mime-to-mml gnus-article-mime-handles)
+ (mime-to-mml ',handles)
(setq gnus-article-mime-handles nil)
- (make-local-hook 'kill-buffer-hook)
(let ((mbl1 mml-buffer-list))
(setq mml-buffer-list mbl)
(set (make-local-variable 'mml-buffer-list) mbl1))
+ ;; LOCAL argument of add-hook differs between GNU Emacs
+ ;; and XEmacs. make-local-hook makes sure they are local.
+ (make-local-hook 'kill-buffer-hook)
(add-hook 'kill-buffer-hook 'mml-destroy-buffers t t)))
`(lambda (no-highlight)
(let ((mail-parse-charset (or gnus-article-charset
(mm-handle-undisplayer handle)
(mm-handle-disposition handle)
(mm-handle-description handle)
- (mm-handle-cache handle)
+ nil
(mm-handle-id handle)))
(setq gnus-article-mime-handles
(mm-merge-handles gnus-article-mime-handles handle))
(gnus-mm-display-part handle))))
(defun gnus-mime-copy-part (&optional handle)
- "Put the the MIME part under point into a new buffer."
+ "Put the MIME part under point into a new buffer."
(interactive)
(gnus-article-check-buffer)
(let* ((handle (or handle (get-text-property (point) 'gnus-data)))
(setq buffer-file-name nil))
(goto-char (point-min)))))
+(defun gnus-mime-print-part (&optional handle)
+ "Print the MIME part under point."
+ (interactive)
+ (gnus-article-check-buffer)
+ (let* ((handle (or handle (get-text-property (point) 'gnus-data)))
+ (contents (and handle (mm-get-part handle)))
+ (file (make-temp-name (expand-file-name "mm." mm-tmp-directory)))
+ (printer (mailcap-mime-info (mm-handle-type handle) "print")))
+ (when contents
+ (if printer
+ (unwind-protect
+ (progn
+ (with-temp-file file
+ (insert contents))
+ (call-process shell-file-name nil
+ (generate-new-buffer " *mm*")
+ nil
+ shell-command-switch
+ (mm-mailcap-command
+ printer file (mm-handle-type handle))))
+ (delete-file file))
+ (with-temp-buffer
+ (insert contents)
+ (gnus-print-buffer))))))
+
(defun gnus-mime-inline-part (&optional handle arg)
"Insert the MIME part under point into the current buffer."
(interactive (list nil current-prefix-arg))
(setq charset
(or (cdr (assq arg
gnus-summary-show-article-charset-alist))
- (read-coding-system "Charset: ")))))
+ (mm-read-coding-system "Charset: ")))))
(forward-line 2)
(mm-insert-inline handle
(if (and charset
(goto-char b)))))
(defun gnus-mime-view-part-as-charset (&optional handle arg)
- "Insert the MIME part under point into the current buffer."
+ "Insert the MIME part under point into the current buffer using the
+specified charset."
(interactive (list nil current-prefix-arg))
(gnus-article-check-buffer)
(let* ((handle (or handle (get-text-property (point) 'gnus-data)))
(let ((gnus-newsgroup-charset
(or (cdr (assq arg
gnus-summary-show-article-charset-alist))
- (read-coding-system "Charset: ")))
+ (mm-read-coding-system "Charset: ")))
(gnus-newsgroup-ignored-charsets 'gnus-all))
(gnus-article-press-button)))))
(defun gnus-mime-internalize-part (&optional handle)
"View the MIME part under point with an internal viewer.
-In no internal viewer is available, use an external viewer."
+If no internal viewer is available, use an external viewer."
(interactive)
(gnus-article-check-buffer)
(let* ((handle (or handle (get-text-property (point) 'gnus-data)))
gnus-newsgroup-ignored-charsets)))
(save-excursion
(unwind-protect
- (let ((win (get-buffer-window (current-buffer) t))
+ (let ((win (gnus-get-buffer-window (current-buffer) t))
(beg (point)))
(when win
(select-window win))
;; This will remove the part.
(mm-display-part handle)
(save-restriction
- (narrow-to-region (point) (1+ (point)))
+ (narrow-to-region (point)
+ (if (eobp) (point) (1+ (point))))
(mm-display-part handle)
;; We narrow to the part itself and
;; then call the treatment functions.
nil id
(gnus-article-mime-total-parts)
(mm-handle-media-type handle)))))
- (select-window window))))
+ (if (window-live-p window)
+ (select-window window)))))
(goto-char point)
(delete-region (gnus-point-at-bol) (progn (forward-line 1) (point)))
(gnus-insert-mime-button
(defun gnus-insert-mime-button (handle gnus-tmp-id &optional displayed)
(let ((gnus-tmp-name
- (or (mail-content-type-get (mm-handle-type handle)
- 'name)
- (mail-content-type-get (mm-handle-disposition handle)
- 'filename)
- (mail-content-type-get (mm-handle-type handle)
- 'url)
+ (or (mail-content-type-get (mm-handle-type handle) 'name)
+ (mail-content-type-get (mm-handle-disposition handle) 'filename)
+ (mail-content-type-get (mm-handle-type handle) 'url)
""))
(gnus-tmp-type (mm-handle-media-type handle))
(gnus-tmp-description
(setq gnus-tmp-type-long (concat gnus-tmp-type
(and (not (equal gnus-tmp-name ""))
(concat "; " gnus-tmp-name))))
- (or (equal gnus-tmp-description "")
- (setq gnus-tmp-type-long (concat " --- " gnus-tmp-type-long)))
+ (unless (equal gnus-tmp-description "")
+ (setq gnus-tmp-type-long (concat " --- " gnus-tmp-type-long)))
(unless (bolp)
(insert "\n"))
(setq b (point))
;;;!!! No, w3 can display everything just fine.
(gnus-mime-display-part (cadr handle)))
((equal (car handle) "multipart/signed")
- (or (memq 'signed gnus-article-wash-types)
- (push 'signed gnus-article-wash-types))
+ (gnus-add-wash-type 'signed)
(gnus-mime-display-security handle))
((equal (car handle) "multipart/encrypted")
- (or (memq 'encrypted gnus-article-wash-types)
- (push 'encrypted gnus-article-wash-types))
+ (gnus-add-wash-type 'encrypted)
(gnus-mime-display-security handle))
;; Other multiparts are handled like multipart/mixed.
(t
"inline")
(mm-attachment-override-p handle))))
(mm-automatic-display-p handle)
- (or (mm-inlined-p handle)
+ (or (and
+ (mm-inlinable-p handle)
+ (mm-inlined-p handle))
(mm-automatic-external-display-p type)))
(setq display t)
(when (equal (mm-handle-media-supertype handle) "text")
(defun gnus-unbuttonized-mime-type-p (type)
"Say whether TYPE is to be unbuttonized."
(unless gnus-inhibit-mime-unbuttonizing
- (catch 'found
- (let ((types gnus-unbuttonized-mime-types))
- (while types
- (when (string-match (pop types) type)
- (throw 'found t)))))))
+ (when (catch 'found
+ (let ((types gnus-unbuttonized-mime-types))
+ (while types
+ (when (string-match (pop types) type)
+ (throw 'found t)))))
+ (not (catch 'found
+ (let ((types gnus-buttonized-mime-types))
+ (while types
+ (when (string-match (pop types) type)
+ (throw 'found t)))))))))
(defun gnus-article-insert-newline ()
"Insert a newline, but mark it as undeletable."
(when ibegend
(goto-char point))))
+(defconst gnus-article-wash-status-strings
+ (let ((alist '((cite "c" "Possible hidden citation text"
+ " " "All citation text visible")
+ (headers "h" "Hidden headers"
+ " " "All headers visible.")
+ (pgp "p" "Encrypted or signed message status hidden"
+ " " "No hidden encryption nor digital signature status")
+ (signature "s" "Signature has been hidden"
+ " " "Signature is visible")
+ (overstrike "o" "Overstrike (^H) characters applied"
+ " " "No overstrike characters applied")
+ (emphasis "e" "/*_Emphasis_*/ characters applied"
+ " " "No /*_emphasis_*/ characters applied")))
+ result)
+ (dolist (entry alist result)
+ (let ((key (nth 0 entry))
+ (on (copy-sequence (nth 1 entry)))
+ (on-help (nth 2 entry))
+ (off (copy-sequence (nth 3 entry)))
+ (off-help (nth 4 entry)))
+ (put-text-property 0 1 'help-echo on-help on)
+ (put-text-property 0 1 'help-echo off-help off)
+ (push (list key on off) result))))
+ "Alist of strings describing wash status in the mode line.
+Each entry has the form (KEY ON OF), where the KEY is a symbol
+representing the particular washing function, ON is the string to use
+in the article mode line when the washing function is active, and OFF
+is the string to use when it is inactive.")
+
+(defun gnus-article-wash-status-entry (key value)
+ (let ((entry (assoc key gnus-article-wash-status-strings)))
+ (if value (nth 1 entry) (nth 2 entry))))
+
(defun gnus-article-wash-status ()
"Return a string which display status of article washing."
(save-excursion
(signature (memq 'signature gnus-article-wash-types))
(overstrike (memq 'overstrike gnus-article-wash-types))
(emphasis (memq 'emphasis gnus-article-wash-types)))
- (format "%c%c%c%c%c%c"
- (if cite ?c ? )
- (if (or headers boring) ?h ? )
- (if (or pgp pem signed encrypted) ?p ? )
- (if signature ?s ? )
- (if overstrike ?o ? )
- (if emphasis ?e ? )))))
+ (concat
+ (gnus-article-wash-status-entry 'cite cite)
+ (gnus-article-wash-status-entry 'headers (or headers boring))
+ (gnus-article-wash-status-entry 'pgp (or pgp pem signed encrypted))
+ (gnus-article-wash-status-entry 'signature signature)
+ (gnus-article-wash-status-entry 'overstrike overstrike)
+ (gnus-article-wash-status-entry 'emphasis emphasis)))))
+
+(defun gnus-add-wash-type (type)
+ "Add a washing of TYPE to the current status."
+ (push type gnus-article-wash-types))
+
+(defun gnus-delete-wash-type (type)
+ "Add a washing of TYPE to the current status."
+ (setq gnus-article-wash-types (delq type gnus-article-wash-types)))
+
+(defun gnus-add-image (category image)
+ "Add IMAGE of CATEGORY to the list of displayed images."
+ (let ((entry (assq category gnus-article-image-alist)))
+ (unless entry
+ (setq entry (list category))
+ (push entry gnus-article-image-alist))
+ (nconc entry (list image))))
+
+(defun gnus-delete-images (category)
+ "Delete all images in CATEGORY."
+ (let ((entry (assq category gnus-article-image-alist)))
+ (dolist (image (cdr entry))
+ (gnus-remove-image image))
+ (setq gnus-article-image-alist (delq entry gnus-article-image-alist))
+ (gnus-delete-wash-type category)))
(defalias 'gnus-article-hide-headers-if-wanted 'gnus-article-maybe-hide-headers)
;; save it to file.
(goto-char (point-max))
(insert "\n")
- (mm-append-to-file (point-min) (point-max) file-name)
+ (let ((file-name-coding-system nnmail-pathname-coding-system))
+ (mm-append-to-file (point-min) (point-max) file-name))
t)))
(defun gnus-narrow-to-page (&optional arg)
(interactive "P")
(gnus-article-check-buffer)
(let ((nosaves
- '("q" "Q" "c" "r" "R" "\C-c\C-f" "m" "a" "f" "F"
- "Zc" "ZC" "ZE" "ZQ" "ZZ" "Zn" "ZR" "ZG" "ZN" "ZP"
- "=" "^" "\M-^" "|"))
- (nosave-but-article
- '("A\r"))
- (nosave-in-article
- '("\C-d"))
- (up-to-top
- '("n" "Gn" "p" "Gp"))
- keys new-sum-point)
+ '("q" "Q" "c" "r" "R" "\C-c\C-f" "m" "a" "f" "F"
+ "Zc" "ZC" "ZE" "ZQ" "ZZ" "Zn" "ZR" "ZG" "ZN" "ZP"
+ "=" "^" "\M-^" "|"))
+ (nosave-but-article
+ '("A\r"))
+ (nosave-in-article
+ '("\C-d"))
+ (up-to-top
+ '("n" "Gn" "p" "Gp"))
+ keys new-sum-point)
(save-excursion
(set-buffer gnus-article-current-summary)
(let (gnus-pick-mode)
- (push (or key last-command-event) unread-command-events)
- (setq keys (if (featurep 'xemacs)
+ (push (or key last-command-event) unread-command-events)
+ (setq keys (if (featurep 'xemacs)
(events-to-keys (read-key-sequence nil))
(read-key-sequence nil)))))
(message "")
(if (or (member keys nosaves)
- (member keys nosave-but-article)
- (member keys nosave-in-article))
- (let (func)
- (save-window-excursion
- (pop-to-buffer gnus-article-current-summary 'norecord)
- ;; We disable the pick minor mode commands.
- (let (gnus-pick-mode)
- (setq func (lookup-key (current-local-map) keys))))
- (if (or (not func)
+ (member keys nosave-but-article)
+ (member keys nosave-in-article))
+ (let (func)
+ (save-window-excursion
+ (pop-to-buffer gnus-article-current-summary 'norecord)
+ ;; We disable the pick minor mode commands.
+ (let (gnus-pick-mode)
+ (setq func (lookup-key (current-local-map) keys))))
+ (if (or (not func)
(numberp func))
- (ding)
- (unless (member keys nosave-in-article)
- (set-buffer gnus-article-current-summary))
- (call-interactively func)
- (setq new-sum-point (point)))
- (when (member keys nosave-but-article)
- (pop-to-buffer gnus-article-buffer 'norecord)))
+ (ding)
+ (unless (member keys nosave-in-article)
+ (set-buffer gnus-article-current-summary))
+ (call-interactively func)
+ (setq new-sum-point (point)))
+ (when (member keys nosave-but-article)
+ (pop-to-buffer gnus-article-buffer 'norecord)))
;; These commands should restore window configuration.
(let ((obuf (current-buffer))
- (owin (current-window-configuration))
- (opoint (point))
- (summary gnus-article-current-summary)
- func in-buffer selected)
- (if not-restore-window
- (pop-to-buffer summary 'norecord)
- (switch-to-buffer summary 'norecord))
- (setq in-buffer (current-buffer))
- ;; We disable the pick minor mode commands.
- (if (and (setq func (let (gnus-pick-mode)
+ (owin (current-window-configuration))
+ (opoint (point))
+ (summary gnus-article-current-summary)
+ func in-buffer selected)
+ (if not-restore-window
+ (pop-to-buffer summary 'norecord)
+ (switch-to-buffer summary 'norecord))
+ (setq in-buffer (current-buffer))
+ ;; We disable the pick minor mode commands.
+ (if (and (setq func (let (gnus-pick-mode)
(lookup-key (current-local-map) keys)))
(functionp func))
- (progn
- (call-interactively func)
- (setq new-sum-point (point))
+ (progn
+ (call-interactively func)
+ (setq new-sum-point (point))
(when (eq in-buffer (current-buffer))
(setq selected (gnus-summary-select-article))
(set-buffer obuf)
(when win
(set-window-point win new-sum-point)))) )
(switch-to-buffer gnus-article-buffer)
- (ding))))))
+ (ding))))))
(defun gnus-article-describe-key (key)
"Display documentation of the function invoked by KEY. KEY is a string."
(if (featurep 'xemacs)
(progn
(push (elt key 0) unread-command-events)
- (setq key (events-to-keys
+ (setq key (events-to-keys
(read-key-sequence "Describe key: "))))
- (setq unread-command-events
- (mapcar
+ (setq unread-command-events
+ (mapcar
(lambda (x) (if (>= x 128) (list 'meta (- x 128)) x))
(string-to-list key)))
(setq key (read-key-sequence "Describe key: "))))
(if (featurep 'xemacs)
(progn
(push (elt key 0) unread-command-events)
- (setq key (events-to-keys
+ (setq key (events-to-keys
(read-key-sequence "Describe key: "))))
- (setq unread-command-events
- (mapcar
+ (setq unread-command-events
+ (mapcar
(lambda (x) (if (>= x 128) (list 'meta (- x 128)) x))
(string-to-list key)))
(setq key (read-key-sequence "Describe key: "))))
(setq gnus-override-method (pop methods)))
(while (not result)
(when (eq gnus-override-method 'current)
- (setq gnus-override-method gnus-current-select-method))
+ (setq gnus-override-method
+ (with-current-buffer gnus-summary-buffer
+ gnus-current-select-method)))
(erase-buffer)
(gnus-kill-all-overlays)
(let ((gnus-newsgroup-name group))
(set-buffer gnus-summary-buffer)
(gnus-summary-update-article do-update-line sparse-header)
(gnus-summary-goto-subject do-update-line nil t)
- (set-window-point (get-buffer-window (current-buffer) t)
+ (set-window-point (gnus-get-buffer-window (current-buffer) t)
(point))
(set-buffer buf))))))
"\C-c\C-w" gnus-article-edit-mode-map)
"f" gnus-article-edit-full-stops))
-(defun gnus-article-edit-mode ()
+(define-derived-mode gnus-article-edit-mode text-mode "Article Edit"
"Major mode for editing articles.
This is an extended text-mode.
\\{gnus-article-edit-mode-map}"
- (interactive)
- (setq major-mode 'gnus-article-edit-mode)
- (setq mode-name "Article Edit")
- (use-local-map gnus-article-edit-mode-map)
(make-local-variable 'gnus-article-edit-done-function)
(make-local-variable 'gnus-prev-winconf)
+ (set (make-local-variable 'font-lock-defaults)
+ '(message-font-lock-keywords t))
(setq buffer-read-only nil)
(buffer-enable-undo)
- (widen)
- (gnus-run-hooks 'text-mode-hook 'gnus-article-edit-mode-hook))
+ (widen))
(defun gnus-article-edit (&optional force)
"Edit the current article.
;;; Internal Variables:
-(defcustom gnus-button-url-regexp "\\b\\(\\(www\\.\\|\\(s?https?\\|ftp\\|file\\|gopher\\|news\\|telnet\\|wais\\|mailto\\):\\)\\(//[-a-zA-Z0-9_.]+:[0-9]*\\)?\\([-a-zA-Z0-9_=!?#$@~`%&*+|\\/:;.,]\\|\\w\\)+\\([-a-zA-Z0-9_=#$@~`%&*+|\\/]\\|\\w\\)\\)"
+(defcustom gnus-button-url-regexp "\\b\\(\\(www\\.\\|\\(s?https?\\|ftp\\|file\\|gopher\\|news\\|telnet\\|wais\\|mailto\\|info\\):\\)\\(//[-a-zA-Z0-9_.]+:[0-9]*\\)?\\([-a-zA-Z0-9_=!?#$@~`%&*+|\\/:;.,]\\|\\w\\)+\\([-a-zA-Z0-9_=#$@~`%&*+|\\/]\\|\\w\\)\\)"
"Regular expression that matches URLs."
:group 'gnus-article-buttons
:type 'regexp)
("\\(<URL: *\\)mailto: *\\([^> \n\t]+\\)>" 0 t gnus-url-mailto 2)
("mailto:\\([-a-zA-Z.@_+0-9%=?]+\\)" 0 t gnus-url-mailto 1)
("\\bmailto:\\([^ \n\t]+\\)" 0 t gnus-url-mailto 1)
+ ;; This is info
+ ("\\binfo:\\(//\\)?\\([^'\">\n\t ]+\\)" 0 t
+ gnus-button-handle-info 2)
;; This is how URLs _should_ be embedded in text...
("<URL: *\\([^<>]*\\)>" 0 t gnus-button-embedded-url 1)
;; Raw URLs.
(integer :tag "Regexp group")))))
(defcustom gnus-header-button-alist
- `(("^\\(References\\|Message-I[Dd]\\):" "<[^>]+>"
+ `(("^\\(References\\|Message-I[Dd]\\):" "<[^<>]+>"
0 t gnus-button-message-id 0)
("^\\(From\\|Reply-To\\):" ": *\\(.+\\)$" 1 t gnus-button-reply 1)
("^\\(Cc\\|To\\):" "[^ \t\n<>,()\"]+@[^ \t\n<>,()\"]+"
(interactive "e")
(set-buffer (window-buffer (posn-window (event-start event))))
(let* ((pos (posn-point (event-start event)))
- (data (get-text-property pos 'gnus-data))
+ (data (get-text-property pos 'gnus-data))
(fun (get-text-property pos 'gnus-callback)))
(goto-char pos)
(when fun
(let ((buffer-read-only nil)
(inhibit-point-motion-hooks t))
(if (text-property-any end (point-max) 'article-type 'signature)
- (gnus-remove-text-properties-when
- 'article-type 'signature end (point-max)
- (cons 'article-type (cons 'signature
- gnus-hidden-properties)))
+ (progn
+ (gnus-delete-wash-type 'signature)
+ (gnus-remove-text-properties-when
+ 'article-type 'signature end (point-max)
+ (cons 'article-type (cons 'signature
+ gnus-hidden-properties))))
+ (gnus-add-wash-type 'signature)
(gnus-add-text-properties-when
'article-type nil end (point-max)
(cons 'article-type (cons 'signature
- gnus-hidden-properties)))))))
+ gnus-hidden-properties)))))
+ (let ((gnus-article-mime-handle-alist-1 gnus-article-mime-handle-alist))
+ (gnus-set-mode-line 'article))))
(defun gnus-button-entry ()
;; Return the first entry in `gnus-button-alist' matching this place.
(when (looking-at "//\\([^/]+\\)/")
(setq server (match-string 1))
(goto-char (match-end 0)))
-
+
(cond
((looking-at "\\(.*@.*\\)")
(setq message-id (match-string 1)))
(group
(gnus-button-fetch-group url)))))
+(defun gnus-button-handle-info (url)
+ "Fetch an info URL."
+ (if (string-match
+ "^\\([^:/]+\\)?/\\(.*\\)"
+ url)
+ (gnus-info-find-node
+ (concat "(" (or (gnus-url-unhex-string (match-string 1 url))
+ "Gnus")
+ ")"
+ (gnus-url-unhex-string (match-string 2 url))))
+ (error "Can't parse %s" url)))
+
(defun gnus-button-message-id (message-id)
"Fetch MESSAGE-ID."
(save-excursion
(if (not (string-match "[:/]" address))
;; This is just a simple group url.
(gnus-group-read-ephemeral-group address gnus-select-method)
- (if (not (string-match "^\\([^:/]+\\)\\(:\\([^/]+\\)/\\)?\\(.*\\)$"
- address))
+ (if (not
+ (string-match
+ "^\\([^:/]+\\)\\(:\\([^/]+\\)\\)?/\\([^/]+\\)\\(/\\([0-9]+\\)\\)?"
+ address))
(error "Can't parse %s" address)
(gnus-group-read-ephemeral-group
(match-string 4 address)
(nntp-address ,(match-string 1 address))
(nntp-port-number ,(if (match-end 3)
(match-string 3 address)
- "nntp")))))))
+ "nntp")))
+ nil nil nil
+ (and (match-end 6) (list (string-to-int (match-string 6 address))))))))
(defun gnus-url-parse-query-string (query &optional downcase)
(let (retval pairs cur key val)
(setq pairs (split-string query "&"))
(while pairs
(setq cur (car pairs)
- pairs (cdr pairs))
+ pairs (cdr pairs))
(if (not (string-match "=" cur))
- nil ; Grace
- (setq key (gnus-url-unhex-string (substring cur 0 (match-beginning 0)))
- val (gnus-url-unhex-string (substring cur (match-end 0) nil)))
- (if downcase
- (setq key (downcase key)))
- (setq cur (assoc key retval))
- (if cur
- (setcdr cur (cons val (cdr cur)))
- (setq retval (cons (list key val) retval)))))
+ nil ; Grace
+ (setq key (gnus-url-unhex-string (substring cur 0 (match-beginning 0)))
+ val (gnus-url-unhex-string (substring cur (match-end 0) nil)))
+ (if downcase
+ (setq key (downcase key)))
+ (setq cur (assoc key retval))
+ (if cur
+ (setcdr cur (cons val (cdr cur)))
+ (setq retval (cons (list key val) retval)))))
retval))
-(defun gnus-url-unhex (x)
- (if (> x ?9)
- (if (>= x ?a)
- (+ 10 (- x ?a))
- (+ 10 (- x ?A)))
- (- x ?0)))
-
-(defun gnus-url-unhex-string (str &optional allow-newlines)
- "Remove %XXX embedded spaces, etc in a url.
-If optional second argument ALLOW-NEWLINES is non-nil, then allow the
-decoding of carriage returns and line feeds in the string, which is normally
-forbidden in URL encoding."
- (setq str (or str ""))
- (let ((tmp "")
- (case-fold-search t))
- (while (string-match "%[0-9a-f][0-9a-f]" str)
- (let* ((start (match-beginning 0))
- (ch1 (gnus-url-unhex (elt str (+ start 1))))
- (code (+ (* 16 ch1)
- (gnus-url-unhex (elt str (+ start 2))))))
- (setq tmp (concat
- tmp (substring str 0 start)
- (cond
- (allow-newlines
- (char-to-string code))
- ((or (= code ?\n) (= code ?\r))
- " ")
- (t (char-to-string code))))
- str (substring str (match-end 0)))))
- (setq tmp (concat tmp str))
- tmp))
-
(defun gnus-url-mailto (url)
;; Send mail to someone
(when (string-match "mailto:/*\\(.*\\)" url)
(setq url (substring url (match-beginning 1) nil)))
(let (to args subject func)
(if (string-match (regexp-quote "?") url)
- (setq to (gnus-url-unhex-string (substring url 0 (match-beginning 0)))
- args (gnus-url-parse-query-string
- (substring url (match-end 0) nil) t))
+ (setq to (gnus-url-unhex-string (substring url 0 (match-beginning 0)))
+ args (gnus-url-parse-query-string
+ (substring url (match-end 0) nil) t))
(setq to (gnus-url-unhex-string url)))
(setq args (cons (list "to" to) args)
- subject (cdr-safe (assoc "subject" args)))
+ subject (cdr-safe (assoc "subject" args)))
(gnus-msg-mail)
(while args
(setq func (intern-soft (concat "message-goto-" (downcase (caar args)))))
(if (fboundp func)
- (funcall func)
- (message-position-on-field (caar args)))
+ (funcall func)
+ (message-position-on-field (caar args)))
(insert (mapconcat 'identity (cdar args) ", "))
(setq args (cdr args)))
(if subject
- (message-goto-body)
+ (message-goto-body)
(message-goto-subject))))
(defun gnus-button-embedded-url (address)
"Go to the next page."
(interactive)
(let ((win (selected-window)))
- (select-window (get-buffer-window gnus-article-buffer t))
+ (select-window (gnus-get-buffer-window gnus-article-buffer t))
(gnus-article-next-page)
(select-window win)))
"Go to the prev page."
(interactive)
(let ((win (selected-window)))
- (select-window (get-buffer-window gnus-article-buffer t))
+ (select-window (gnus-get-buffer-window gnus-article-buffer t))
(gnus-article-prev-page)
(select-window win)))
"Go to the next page."
(interactive "P")
(let ((win (selected-window)))
- (select-window (get-buffer-window gnus-article-buffer t))
+ (select-window (gnus-get-buffer-window gnus-article-buffer t))
(gnus-article-next-page)
(select-window win)))
"Go to the prev page."
(interactive "P")
(let ((win (selected-window)))
- (select-window (get-buffer-window gnus-article-buffer t))
+ (select-window (gnus-get-buffer-window gnus-article-buffer t))
(gnus-article-prev-page)
(select-window win)))
(unless func
(error (format "Can't find the encrypt protocol %s" protocol)))
(if (equal gnus-newsgroup-name "nndraft:drafts")
- (error "Can't encrypt the article in group nndraft:drafts."))
+ (error "Can't encrypt the article in group nndraft:drafts"))
(if (equal gnus-newsgroup-name "nndraft:queue")
- (error "Don't encrypt the article in group nndraft:queue."))
+ (error "Don't encrypt the article in group nndraft:queue"))
(gnus-summary-iterate n
(save-excursion
(set-buffer gnus-summary-buffer)
(defun gnus-mime-security-verify-or-decrypt (handle)
(mm-remove-parts (cdr handle))
(let ((region (mm-handle-multipart-ctl-parameter handle 'gnus-region))
- buffer-read-only)
+ point buffer-read-only)
+ (if region
+ (goto-char (car region)))
+ (save-restriction
+ (narrow-to-region (point) (point))
+ (with-current-buffer (mm-handle-multipart-original-buffer handle)
+ (let* ((mm-verify-option 'known)
+ (mm-decrypt-option 'known)
+ (nparts (mm-possibly-verify-or-decrypt (cdr handle) handle)))
+ (unless (eq nparts (cdr handle))
+ (mm-destroy-parts (cdr handle))
+ (setcdr handle nparts))))
+ (setq point (point))
+ (gnus-mime-display-security handle)
+ (goto-char (point-max)))
(when region
- (delete-region (car region) (cdr region))
+ (delete-region (point) (cdr region))
(set-marker (car region) nil)
- (set-marker (cdr region) nil)))
- (with-current-buffer (mm-handle-multipart-original-buffer handle)
- (let* ((mm-verify-option 'known)
- (mm-decrypt-option 'known)
- (nparts (mm-possibly-verify-or-decrypt (cdr handle) handle)))
- (unless (eq nparts (cdr handle))
- (mm-destroy-parts (cdr handle))
- (setcdr handle nparts))))
- (let ((point (point))
- buffer-read-only)
- (gnus-mime-display-security handle)
+ (set-marker (cdr region) nil))
(goto-char point)))
(defun gnus-mime-security-show-details (handle)
gnus-mime-security-button-line-format)
(forward-char -1))
(forward-char)
+ (save-restriction
+ (narrow-to-region (point) (point))
+ (gnus-insert-mime-security-button handle))
(delete-region (point)
(or (text-property-not-all
(point) (point-max)
- 'gnus-line-format
- gnus-mime-security-button-line-format)
- (point-max)))
- (gnus-insert-mime-security-button handle))
+ 'gnus-line-format
+ gnus-mime-security-button-line-format)
+ (point-max))))
(if (gnus-buffer-live-p gnus-mime-security-details-buffer)
(with-current-buffer gnus-mime-security-details-buffer
(erase-buffer)
(defun gnus-mime-display-security (handle)
(save-restriction
(narrow-to-region (point) (point))
- (gnus-insert-mime-security-button handle)
+ (unless (gnus-unbuttonized-mime-type-p (car handle))
+ (gnus-insert-mime-security-button handle))
(gnus-mime-display-mixed (cdr handle))
(unless (bolp)
(insert "\n"))
- (let ((gnus-mime-security-button-line-format
- gnus-mime-security-button-end-line-format))
- (gnus-insert-mime-security-button handle))
+ (unless (gnus-unbuttonized-mime-type-p (car handle))
+ (let ((gnus-mime-security-button-line-format
+ gnus-mime-security-button-end-line-format))
+ (gnus-insert-mime-security-button handle)))
(mm-set-handle-multipart-parameter
handle 'gnus-region
(cons (set-marker (make-marker) (point-min))
;;; gnus-bcklg.el --- backlog functions for Gnus
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;; Keywords: news
(defun gnus-backlog-shutdown ()
"Clear all backlog variables and buffers."
+ (interactive)
(when (get-buffer gnus-backlog-buffer)
(kill-buffer gnus-backlog-buffer))
(setq gnus-backlog-hashtb nil
;;; gnus-cache.el --- cache interface for Gnus
-;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
(when (and number
(> number 0) ; Reffed article.
(or force
- (and (or (not gnus-cacheable-groups)
- (string-match gnus-cacheable-groups group))
- (or (not gnus-uncacheable-groups)
- (not (string-match
- gnus-uncacheable-groups group)))
+ (and (gnus-cache-fully-p group)
(gnus-cache-member-of-class
gnus-cache-enter-articles ticked dormant unread)))
(not (file-exists-p (setq file (gnus-cache-file-name
(nnheader-insert-nov headers)
;; Update the active info.
(set-buffer gnus-summary-buffer)
- (gnus-cache-update-active group number)
+ (gnus-cache-possibly-update-active group (cons number number))
(push article gnus-newsgroup-cached)
(gnus-summary-update-secondary-mark article))
t))))))
(defun gnus-cache-possibly-remove-articles-1 ()
"Possibly remove some of the removable articles."
- (unless (eq gnus-use-cache 'passive)
+ (when (gnus-cache-fully-p gnus-newsgroup-name)
(let ((articles gnus-cache-removable-articles)
(cache-articles gnus-newsgroup-cached)
article)
;; unsuccessful), so we use the cached headers exclusively.
(set-buffer nntp-server-buffer)
(erase-buffer)
- (let ((coding-system-for-read
+ (let ((coding-system-for-read
gnus-cache-overview-coding-system))
(insert-file-contents cache-file))
'nov)
(while cached
(gnus-summary-goto-subject (pop cached) t))))
-(defalias 'gnus-summary-limit-include-cached
- 'gnus-summary-insert-cached-articles)
+(defun gnus-summary-limit-include-cached ()
+ "Limit the summary buffer to articles that are cached."
+ (interactive)
+ (let ((cached (sort (copy-sequence gnus-newsgroup-cached) '>))
+ (gnus-verbose (max 6 gnus-verbose)))
+ (if cached
+ (progn
+ (gnus-summary-limit cached)
+ (gnus-summary-position-point))
+ (gnus-message 3 "No cached articles for this group"))))
;;; Internal functions.
(save-excursion
(set-buffer cache-buf)
(erase-buffer)
- (let ((coding-system-for-read
+ (let ((coding-system-for-read
gnus-cache-overview-coding-system))
- (insert-file-contents
+ (insert-file-contents
(or file (gnus-cache-file-name group ".overview"))))
(goto-char (point-min))
(insert "\n")
(save-excursion
(set-buffer cache-buf)
(erase-buffer)
- (let ((coding-system-for-read
+ (let ((coding-system-for-read
gnus-cache-coding-system))
(insert-file-contents (gnus-cache-file-name group (car cached))))
(goto-char (point-min))
;; Mark the active hashtb as unaltered.
(setq gnus-cache-active-altered nil)))
+(defun gnus-cache-possibly-update-active (group active)
+ "Update active info bounds of GROUP with ACTIVE if necessary.
+The update is performed if ACTIVE contains a higher or lower bound
+than the current."
+ (let ((lower t) (higher t))
+ (if gnus-cache-active-hashtb
+ (let ((cache-active (gnus-gethash group gnus-cache-active-hashtb)))
+ (when cache-active
+ (unless (< (car active) (car cache-active))
+ (setq lower nil))
+ (unless (> (cdr active) (cdr cache-active))
+ (setq higher nil))))
+ (gnus-cache-read-active))
+ (when lower
+ (gnus-cache-update-active group (car active) t))
+ (when higher
+ (gnus-cache-update-active group (cdr active)))))
+
(defun gnus-cache-update-active (group number &optional low)
"Update the upper bound of the active info of GROUP to NUMBER.
If LOW, update the lower bound instead."
(interactive "FMove the cache tree to: ")
(rename-file gnus-cache-directory dir))
+(defun gnus-cache-fully-p (&optional group)
+ "Returns non-nil if the cache should be fully used.
+If GROUP is non-nil, also cater to `gnus-cacheable-groups' and
+`gnus-uncacheable-groups'."
+ (and gnus-use-cache
+ (not (eq gnus-use-cache 'passive))
+ (if (null group)
+ t
+ (and (or (not gnus-cacheable-groups)
+ (string-match gnus-cacheable-groups group))
+ (or (not gnus-uncacheable-groups)
+ (not (string-match gnus-uncacheable-groups group)))))))
+
+
(provide 'gnus-cache)
;;; gnus-cache.el ends here
-;;; gnus-cite.el --- parse citations in articles for Gnus -*- coding: iso-latin-1 -*-
+;;; gnus-cite.el --- parse citations in articles for Gnus
-;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
;; Author: Per Abhiddenware
gnus-hidden-properties))
(point (point-min))
found beg end start)
- (while (setq point
- (text-property-any point (point-max)
+ (while (setq point
+ (text-property-any point (point-max)
'gnus-callback
'gnus-article-toggle-cited-text))
(setq found t)
(setq beg nil)
(setq end (point-marker))))))
(when (and beg end)
+ (gnus-add-wash-type 'cite)
;; We use markers for the end-points to facilitate later
;; wrapping and mangling of text.
(setq beg (set-marker (make-marker) beg)
(and (> arg 0) (not hidden))
(and (< arg 0) hidden))
(if hidden
- (gnus-remove-text-properties-when
- 'article-type 'cite beg end
- (cons 'article-type (cons 'cite
- gnus-hidden-properties)))
+ (progn
+ ;; Can't remove 'cite from g-a-wash-types here because
+ ;; multiple citations may be hidden -jas
+ (gnus-remove-text-properties-when
+ 'article-type 'cite beg end
+ (cons 'article-type (cons 'cite
+ gnus-hidden-properties))))
+ (gnus-add-wash-type 'cite)
(gnus-add-text-properties-when
- 'article-type nil beg end
+ 'article-type nil beg end
(cons 'article-type (cons 'cite
gnus-hidden-properties))))
+ (let ((gnus-article-mime-handle-alist-1 gnus-article-mime-handle-alist))
+ (gnus-set-mode-line 'article))
(save-excursion
(goto-char start)
(gnus-delete-line)
(goto-char (point-min))
(forward-line (1- number))
(cond ((get-text-property (point) 'invisible)
+ ;; Can't remove 'cite from g-a-wash-types here because
+ ;; multiple citations may be hidden -jas
(remove-text-properties (point) (progn (forward-line 1) (point))
gnus-hidden-properties))
((assq number gnus-cite-attribution-alist))
(t
+ (gnus-add-wash-type 'cite)
(gnus-add-text-properties
(point) (progn (forward-line 1) (point))
(nconc (list 'article-type 'cite)
- gnus-hidden-properties))))))))
+ gnus-hidden-properties))))
+ (let ((gnus-article-mime-handle-alist-1
+ gnus-article-mime-handle-alist))
+ (gnus-set-mode-line 'article))))))
(defun gnus-cite-find-prefix (line)
;; Return citation prefix for LINE.
;;; gnus-cus.el --- customization commands for Gnus
;;
-;; Copyright (C) 1996,1999, 2000 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1999, 2000, 2001 Free Software Foundation, Inc.
;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
;; Keywords: news
;;; Widgets:
-;; There should be special validation for this.
-(define-widget 'gnus-email-address 'string
- "An email address")
-
(defun gnus-custom-mode ()
"Major mode for editing Gnus customization buffers.
`immediate'.")
(expiry-target (choice :tag "Expiry Target"
- :value delete
- (const delete)
- (function :format "%v" nnmail-)
- string) "\
+ :value delete
+ (const delete)
+ (function :format "%v" nnmail-)
+ string) "\
Where expired messages end up.
Overrides `nnmail-expiry-target', which see.")
(display (choice :tag "Display"
:value default
(const all)
- (const default)) "\
+ (integer)
+ (const default)
+ (sexp :tag "Other")) "\
Which articles to display on entering the group.
`all'
Display all articles, both read and unread.
+`integer'
+ Display the last NUMBER articles in the group. This is the same as
+ entering the group with C-u NUMBER.
+
`default'
Display the default visible articles, which normally includes
- unread and ticked articles.")
+ unread and ticked articles.
+
+`Other'
+ Display the articles that satisfy the S-expression. The S-expression
+ should be in an array form.")
(comment (string :tag "Comment") "\
An arbitrary comment on the group.")
Always display this group, even when there are no unread articles
in it..")
- (highlight-words
+ (highlight-words
(choice :tag "Highlight words"
:value nil
(repeat (list (regexp :tag "Highlight regexp")
(number :tag "Group for entire word" 0)
(number :tag "Group for displayed part" 0)
- (symbol :tag "Face"
+ (symbol :tag "Face"
gnus-emphasis-highlight-words))))
"highlight regexps.
See gnus-emphasis-alist.")
(choice :tag "Posting style"
:value nil
(repeat (list
- (choice :tag "Type"
+ (choice :tag "Type"
:value nil
(const signature)
- (const signature-file)
- (const organization)
- (const address)
- (const name)
- (const body))
+ (const signature-file)
+ (const organization)
+ (const address)
+ (const name)
+ (const body))
(string :format "%v"))))
"post style.
See gnus-posting-styles."))
(defconst gnus-extra-topic-parameters
'((subscribe (regexp :tag "Subscribe") "\
-If `gnus-subscribe-newsgroup-method' or
+If `gnus-subscribe-newsgroup-method' or
`gnus-subscribe-options-newsgroup-method' is set to
`gnus-subscribe-topics', new groups that matches this regexp will
-automatically be subscribed to this topic"))
+automatically be subscribed to this topic")
+ (subscribe-level (integer :tag "Subscribe Level" :value 1) "\
+If this topic parameter is set, when new groups are subscribed
+automatically under this topic (via the `subscribe' topic parameter)
+assign this level to the group, rather than the default level
+set in `gnus-level-default-subscribed'"))
"Alist of topic parameters that are not also group parameters.
Each entry has the form (NAME TYPE DOC), where NAME is the parameter
(const :format "" ,(nth 0 entry))
,(nth 1 entry)))
(append (reverse gnus-group-parameters-more)
- gnus-group-parameters
+ gnus-group-parameters
(if group
gnus-extra-group-parameters
gnus-extra-topic-parameters)))))
This can be changed using the `\\[gnus-score-change-score-file]' command."
(interactive (list gnus-current-score-file))
(unless file
- (error (format "No score file for %s."
+ (error (format "No score file for %s"
(gnus-group-decoded-name gnus-newsgroup-name))))
(let ((scores (gnus-score-load file))
(types (mapcar (lambda (entry)
--- /dev/null
+;;; gnus-delay.el --- Delayed posting of articles
+
+;; Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+
+;; Author: Kai Großjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+;; Keywords: mail, news, extensions
+
+;; This file 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 2, or (at your option)
+;; any later version.
+
+;; This file 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 GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; Provide delayed posting of articles.
+
+;;; Todo:
+
+;; * `gnus-delay-send-queue' barfs when group does not exist.
+;; * Integrate gnus-delay.el into the rest of Gnus automatically. How
+;; should this be done? Basically, we need to do what
+;; `gnus-delay-initialize' does. But in which files?
+
+;;; Code:
+
+(require 'nndraft)
+(require 'gnus-draft)
+
+;;;###autoload
+(defgroup gnus-delay nil
+ "Arrange for sending postings later."
+ :group 'gnus)
+
+(defcustom gnus-delay-group "delayed"
+ "Group name for storing delayed articles."
+ :type 'string
+ :group 'gnus-delay)
+
+(defcustom gnus-delay-header "X-Gnus-Delayed"
+ "Header name for storing info about delayed articles."
+ :type 'string
+ :group 'gnus-delay)
+
+(defcustom gnus-delay-default-delay "3d"
+ "*Default length of delay."
+ :type 'string
+ :group 'gnus-delay)
+
+(defcustom gnus-delay-default-hour 8
+ "*If deadline is given as date, then assume this time of day."
+ :type 'integer
+ :group 'gnus-delay)
+
+;;;###autoload
+(defun gnus-delay-article (delay)
+ "Delay this article by some time.
+DELAY is a string, giving the length of the time. Possible values are:
+
+* <digits><units> for <units> in minutes (`m'), hours (`h'), days (`d'),
+ weeks (`w'), months (`M'), or years (`Y');
+
+* YYYY-MM-DD for a specific date. The time of day is given by the
+ variable `gnus-delay-default-hour', minute and second are zero.
+
+* hh:mm for a specific time. Use 24h format. If it is later than this
+ time, then the deadline is tomorrow, else today."
+ (interactive
+ (list (read-string
+ "Target date (YYYY-MM-DD) or length of delay (units in [mhdwMY]): "
+ gnus-delay-default-delay)))
+ (let (num unit days year month day hour minute deadline)
+ (cond ((string-match
+ "\\([0-9][0-9][0-9]?[0-9]?\\)-\\([0-9]+\\)-\\([0-9]+\\)"
+ delay)
+ (setq year (string-to-number (match-string 1 delay))
+ month (string-to-number (match-string 2 delay))
+ day (string-to-number (match-string 3 delay)))
+ (setq deadline
+ (message-make-date
+ (encode-time 0 0 ; second and minute
+ gnus-delay-default-hour
+ day month year))))
+ ((string-match "\\([0-9]+\\):\\([0-9]+\\)" delay)
+ (setq hour (string-to-number (match-string 1 delay))
+ minute (string-to-number (match-string 2 delay)))
+ ;; Use current time, except...
+ (setq deadline (apply 'vector (decode-time (current-time))))
+ ;; ... for minute and hour.
+ (aset deadline 1 minute)
+ (aset deadline 2 hour)
+ ;; Convert to seconds.
+ (setq deadline (time-to-seconds (apply 'encode-time
+ (append deadline nil))))
+ ;; If this time has passed already, add a day.
+ (when (< deadline (time-to-seconds (current-time)))
+ (setq deadline (+ 3600 deadline))) ;3600 secs/day
+ ;; Convert seconds to date header.
+ (setq deadline (message-make-date
+ (seconds-to-time deadline))))
+ ((string-match "\\([0-9]+\\)\\s-*\\([mhdwMY]\\)" delay)
+ (setq num (match-string 1 delay))
+ (setq unit (match-string 2 delay))
+ ;; Start from seconds, then multiply into needed units.
+ (setq num (string-to-number num))
+ (cond ((string= unit "Y")
+ (setq delay (* num 60 60 24 365)))
+ ((string= unit "M")
+ (setq delay (* num 60 60 24 30)))
+ ((string= unit "w")
+ (setq delay (* num 60 60 24 7)))
+ ((string= unit "d")
+ (setq delay (* num 60 60 24)))
+ ((string= unit "h")
+ (setq delay (* num 60 60)))
+ (t
+ (setq delay (* num 60))))
+ (setq deadline (message-make-date
+ (seconds-to-time (+ (time-to-seconds (current-time))
+ delay)))))
+ (t (error "Malformed delay `%s'" delay)))
+ (message-add-header (format "%s: %s" gnus-delay-header deadline)))
+ (set-buffer-modified-p t)
+ (nndraft-request-create-group gnus-delay-group)
+ (message-disassociate-draft)
+ (nndraft-request-associate-buffer gnus-delay-group)
+ (save-buffer 0)
+ (kill-buffer (current-buffer))
+ (message-do-actions message-postpone-actions))
+
+;;;###autoload
+(defun gnus-delay-send-queue ()
+ "Send all the delayed messages that are due now."
+ (interactive)
+ (save-excursion
+ (let* ((group (format "nndraft:%s" gnus-delay-group))
+ articles
+ article deadline)
+ (when (gnus-gethash group gnus-newsrc-hashtb)
+ (gnus-activate-group group)
+ (setq articles (nndraft-articles))
+ (while (setq article (pop articles))
+ (gnus-request-head article group)
+ (set-buffer nntp-server-buffer)
+ (goto-char (point-min))
+ (if (re-search-forward
+ (concat "^" (regexp-quote gnus-delay-header) ":\\s-+")
+ nil t)
+ (progn
+ (setq deadline (nnheader-header-value))
+ (setq deadline (apply 'encode-time
+ (parse-time-string deadline)))
+ (setq deadline (time-since deadline))
+ (when (and (>= (nth 0 deadline) 0)
+ (>= (nth 1 deadline) 0))
+ (message "Sending delayed article %d" article)
+ (gnus-draft-send article group)
+ (message "Sending delayed article %d...done" article)))
+ (message "Delay header missing for article %d" article)))))))
+
+;;;###autoload
+(defun gnus-delay-initialize (&optional no-keymap no-check)
+ "Initialize the gnus-delay package.
+This sets up a key binding in `message-mode' to delay a message.
+This tells Gnus to look for delayed messages after getting new news.
+
+The optional arg NO-KEYMAP is ignored.
+Checking delayed messages is skipped if optional arg NO-CHECK is non-nil."
+ (unless no-check
+ (add-hook 'gnus-get-new-news-hook 'gnus-delay-send-queue)))
+
+(provide 'gnus-delay)
+
+;; Local Variables:
+;; coding: iso-8859-1
+;; End:
+
+;;; gnus-delay.el ends here
(if (not (stringp time))
time
(let* ((now (current-time))
- ;; obtain NOW as discrete components -- make a vector for speed
- (nowParts (decode-time now))
- ;; obtain THEN as discrete components
- (thenParts (parse-time-string time))
- (thenHour (elt thenParts 2))
- (thenMin (elt thenParts 1))
- ;; convert time as elements into number of seconds since EPOCH.
- (then (encode-time 0
- thenMin
- thenHour
- ;; If THEN is earlier than NOW, make it
- ;; same time tomorrow. Doc for encode-time
- ;; says that this is OK.
- (+ (elt nowParts 3)
- (if (or (< thenHour (elt nowParts 2))
- (and (= thenHour (elt nowParts 2))
- (<= thenMin (elt nowParts 1))))
- 1 0))
- (elt nowParts 4)
- (elt nowParts 5)
- (elt nowParts 6)
- (elt nowParts 7)
- (elt nowParts 8)))
- ;; calculate number of seconds between NOW and THEN
- (diff (+ (* 65536 (- (car then) (car now)))
- (- (cadr then) (cadr now)))))
+ ;; obtain NOW as discrete components -- make a vector for speed
+ (nowParts (decode-time now))
+ ;; obtain THEN as discrete components
+ (thenParts (parse-time-string time))
+ (thenHour (elt thenParts 2))
+ (thenMin (elt thenParts 1))
+ ;; convert time as elements into number of seconds since EPOCH.
+ (then (encode-time 0
+ thenMin
+ thenHour
+ ;; If THEN is earlier than NOW, make it
+ ;; same time tomorrow. Doc for encode-time
+ ;; says that this is OK.
+ (+ (elt nowParts 3)
+ (if (or (< thenHour (elt nowParts 2))
+ (and (= thenHour (elt nowParts 2))
+ (<= thenMin (elt nowParts 1))))
+ 1 0))
+ (elt nowParts 4)
+ (elt nowParts 5)
+ (elt nowParts 6)
+ (elt nowParts 7)
+ (elt nowParts 8)))
+ ;; calculate number of seconds between NOW and THEN
+ (diff (+ (* 65536 (- (car then) (car now)))
+ (- (cadr then) (cadr now)))))
;; return number of timesteps in the number of seconds
(round (/ diff gnus-demon-timestep)))))
--- /dev/null
+;;; gnus-diary.el --- Wrapper around the NNDiary Gnus backend
+
+;; Copyright (C) 1999-2001 Didier Verna.
+
+;; Author: Didier Verna <didier@xemacs.org>
+;; Maintainer: Didier Verna <didier@xemacs.org>
+;; Created: Tue Jul 20 10:42:55 1999
+;; Last Revision: Wed Sep 12 12:31:09 2001
+;; Keywords: calendar mail news
+
+;; This file is part of Gnus.
+
+;; Gnus 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 2 of the License, or
+;; (at your option) any later version.
+
+;; Gnus 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+;;; Commentary:
+
+;; Contents management by FCM version 0.1.
+
+;; Description:
+;; ===========
+
+;; Gnus-Diary is a wrapper around the NNDiary Gnus backend. It is here to
+;; make your nndiary-user life easier in different ways. So, you don't have
+;; to use it if you don't want to. But, really, you should.
+
+;; Gnus-Diary offers the following features on top of the NNDiary backend:
+
+;; - A nice summary line format:
+;; Displaying diary messages in standard summary line format (usually
+;; something like "<From Joe>: <Subject>") is pretty useless. Most of the
+;; time, you're the one who wrote the message, and you mostly want to see
+;; the event's date. Gnus-Diary offers you a nice summary line format
+;; which will do this. By default, a summary line will appear like this:
+;;
+;; <Event Date>: <Subject> <Remaining time>
+;;
+;; for example, here's how Joe's birthday is displayed in my
+;; "nndiary:birhdays" summary buffer (the message is expirable, but will
+;; never be deleted, as it specifies a regular event):
+;;
+;; E Sat, Sep 22 01, 12:00: Joe's birthday (in 6 months, 1 week)
+
+;; - More article sorting functions:
+;; Gnus-Diary adds a new sorting function called
+;; `gnus-summary-sort-by-schedule'. This function lets you organize your
+;; diary summary buffers from the closest event to the farthest one.
+
+;; - Automatic generation of diary group parameters:
+;; When you create a new diary group, or visit one, Gnus-Diary checks your
+;; group parameters, and if needed, sets the summary line format to the
+;; diary-specific value, adds the diary-specific sorting functions, and
+;; also adds the different `X-Diary-*' headers to the group's
+;; posting-style. It is then easier to send a diary message, because if
+;; you use `C-u a' or `C-u m' on a diary group to prepare a message, these
+;; headers will be inserted automatically (but not filled with proper
+;; values yet).
+
+;; - An interactive mail-to-diary convertion function:
+;; The function `gnus-diary-check-message' ensures that the current message
+;; contains all the required diary headers, and prompts you for values /
+;; correction if needed. This function is hooked in the nndiary backend so
+;; that moving an article to an nndiary group will trigger it
+;; automatically. It is also bound to `C-c D c' in message-mode and
+;; article-edit-mode in order to ease the process of converting a usual
+;; mail to a diary one. This function takes a prefix argument which will
+;; force prompting of all diary headers, regardless of their
+;; presence/validity. That way, you can very easily reschedule a diary
+;; message for instance.
+
+
+;; Usage:
+;; =====
+
+;; 0/ Don't use any `gnus-user-format-function-[d|D]'. Gnus-Diary provides
+;; both of these (sorry if you used them before).
+;; 1/ Add '(require 'gnus-diary) to your gnusrc file.
+;; 2/ Customize your gnus-diary options to suit your needs.
+
+
+
+;; Bugs / Todo:
+;; ===========
+
+
+;;; Code:
+
+(require 'nndiary)
+(require 'message)
+(require 'gnus-art)
+
+(defgroup gnus-diary nil
+ "Utilities on top of the nndiary backend for Gnus.")
+
+(defcustom gnus-diary-summary-line-format "%U%R%z %uD: %(%s%) (%ud)\n"
+ "*Summary line format for nndiary groups."
+ :type 'string
+ :group 'gnus-diary
+ :group 'gnus-summary-format)
+
+(defcustom gnus-diary-time-format "%a, %b %e %y, %H:%M"
+ "*Time format to display appointements in nndiary summary buffers.
+Please refer to `format-time-string' for information on possible values."
+ :type 'string
+ :group 'gnus-diary)
+
+(defcustom gnus-diary-delay-format-function 'gnus-diary-delay-format-english
+ "*Function called to format a diary delay string.
+It is passed two arguments. The first one is non nil if the delay is in
+the past. The second one is of the form ((NUM . UNIT) ...) where NUM is
+an integer and UNIT is one of 'year 'month 'week 'day 'hour or 'minute.
+It should return strings like \"In 2 months, 3 weeks\", \"3 hours,
+1 minute ago\" and so on.
+
+There are currently two built-in format functions:
+`gnus-diary-delay-format-english' (the default)
+`gnus-diary-delay-format-french'"
+ :type '(choice (const :tag "english" gnus-diary-delay-format-english)
+ (const :tag "french" gnus-diary-delay-format-french)
+ (symbol :tag "other"))
+ :group 'gnus-diary)
+
+(defconst gnus-diary-version nndiary-version
+ "Current Diary backend version.")
+
+
+;; Compatibility functions ==================================================
+
+(eval-and-compile
+ (if (fboundp 'kill-entire-line)
+ (defalias 'gnus-diary-kill-entire-line 'kill-entire-line)
+ (defun gnus-diary-kill-entire-line ()
+ (beginning-of-line)
+ (let ((kill-whole-line t))
+ (kill-line)))))
+
+
+;; Summary line format ======================================================
+
+(defun gnus-diary-delay-format-french (past delay)
+ (if (null delay)
+ "maintenant!"
+ ;; Keep only a precision of two degrees
+ (and (> (length delay) 1) (setf (nthcdr 2 delay) nil))
+ (concat (if past "il y a " "dans ")
+ (let ((str "")
+ del)
+ (while (setq del (pop delay))
+ (setq str (concat str
+ (int-to-string (car del)) " "
+ (cond ((eq (cdr del) 'year)
+ "an")
+ ((eq (cdr del) 'month)
+ "mois")
+ ((eq (cdr del) 'week)
+ "semaine")
+ ((eq (cdr del) 'day)
+ "jour")
+ ((eq (cdr del) 'hour)
+ "heure")
+ ((eq (cdr del) 'minute)
+ "minute"))
+ (unless (or (eq (cdr del) 'month)
+ (= (car del) 1))
+ "s")
+ (if delay ", "))))
+ str))))
+
+
+(defun gnus-diary-delay-format-english (past delay)
+ (if (null delay)
+ "now!"
+ ;; Keep only a precision of two degrees
+ (and (> (length delay) 1) (setf (nthcdr 2 delay) nil))
+ (concat (unless past "in ")
+ (let ((str "")
+ del)
+ (while (setq del (pop delay))
+ (setq str (concat str
+ (int-to-string (car del)) " "
+ (symbol-name (cdr del))
+ (and (> (car del) 1) "s")
+ (if delay ", "))))
+ str)
+ (and past " ago"))))
+
+
+(defun gnus-diary-header-schedule (headers)
+ ;; Same as `nndiary-schedule', but given a set of headers HEADERS
+ (mapcar
+ (lambda (elt)
+ (let ((head (cdr (assoc (intern (format "X-Diary-%s" (car elt)))
+ headers))))
+ (when head
+ (nndiary-parse-schedule-value head (cadr elt) (caddr elt)))))
+ nndiary-headers))
+
+;; #### NOTE: Gnus sometimes gives me a HEADER not corresponding to any
+;; message, with all fields set to nil here. I don't know what it is for, and
+;; I just ignore it.
+(defun gnus-user-format-function-d (header)
+ ;; Returns an aproximative delay string for the next occurence of this
+ ;; message. The delay is given only in the first non zero unit.
+ ;; Code partly stolen from article-make-date-line
+ (let* ((extras (mail-header-extra header))
+ (sched (gnus-diary-header-schedule extras))
+ (occur (nndiary-next-occurence sched (current-time)))
+ (now (current-time))
+ (real-time (subtract-time occur now)))
+ (if (null real-time)
+ "?????"
+ (let* ((sec (+ (* (float (car real-time)) 65536) (cadr real-time)))
+ (past (< sec 0))
+ delay)
+ (and past (setq sec (- sec)))
+ (unless (zerop sec)
+ ;; This is a bit convoluted, but basically we go through the time
+ ;; units for years, weeks, etc, and divide things to see whether
+ ;; that results in positive answers.
+ (let ((units `((year . ,(* 365.25 24 3600))
+ (month . ,(* 31 24 3600))
+ (week . ,(* 7 24 3600))
+ (day . ,(* 24 3600))
+ (hour . 3600)
+ (minute . 60)))
+ unit num)
+ (while (setq unit (pop units))
+ (unless (zerop (setq num (ffloor (/ sec (cdr unit)))))
+ (setq delay (append delay `((,(floor num) . ,(car unit))))))
+ (setq sec (- sec (* num (cdr unit)))))))
+ (funcall gnus-diary-delay-format-function past delay)))
+ ))
+
+;; #### NOTE: Gnus sometimes gives me a HEADER not corresponding to any
+;; message, with all fields set to nil here. I don't know what it is for, and
+;; I just ignore it.
+(defun gnus-user-format-function-D (header)
+ ;; Returns a formatted time string for the next occurence of this message.
+ (let* ((extras (mail-header-extra header))
+ (sched (gnus-diary-header-schedule extras))
+ (occur (nndiary-next-occurence sched (current-time))))
+ (format-time-string gnus-diary-time-format occur)))
+
+
+;; Article sorting functions ================================================
+
+(defun gnus-article-sort-by-schedule (h1 h2)
+ (let* ((now (current-time))
+ (e1 (mail-header-extra h1))
+ (e2 (mail-header-extra h2))
+ (s1 (gnus-diary-header-schedule e1))
+ (s2 (gnus-diary-header-schedule e2))
+ (o1 (nndiary-next-occurence s1 now))
+ (o2 (nndiary-next-occurence s2 now)))
+ (if (and (= (car o1) (car o2)) (= (cadr o1) (cadr o2)))
+ (< (mail-header-number h1) (mail-header-number h2))
+ (time-less-p o1 o2))))
+
+
+(defun gnus-thread-sort-by-schedule (h1 h2)
+ (gnus-article-sort-by-schedule (gnus-thread-header h1)
+ (gnus-thread-header h2)))
+
+(defun gnus-summary-sort-by-schedule (&optional reverse)
+ "Sort nndiary summary buffers by schedule of appointements.
+Optional prefix (or REVERSE argument) means sort in reverse order."
+ (interactive "P")
+ (gnus-summary-sort 'schedule reverse))
+
+(defvar gnus-summary-misc-menu) ;; Avoid byte compiler warning.
+(add-hook 'gnus-summary-menu-hook
+ (lambda ()
+ (easy-menu-add-item gnus-summary-misc-menu
+ '("Sort")
+ ["Sort by schedule"
+ gnus-summary-sort-by-schedule
+ (eq (car (gnus-find-method-for-group
+ gnus-newsgroup-name))
+ 'nndiary)]
+ "Sort by number")))
+
+
+
+;; Group parameters autosetting =============================================
+
+(defun gnus-diary-update-group-parameters (group)
+ ;; Ensure that nndiary groups have convenient group parameters:
+ ;; - a posting style containing X-Diary headers
+ ;; - a nice summary line format
+ ;; - NNDiary specific sorting by schedule functions
+ ;; In general, try not to mess with what the user might have modified.
+ (let ((posting-style (gnus-group-get-parameter group 'posting-style t)))
+ ;; Posting style:
+ (mapcar (lambda (elt)
+ (let ((header (format "X-Diary-%s" (car elt))))
+ (unless (assoc header posting-style)
+ (setq posting-style (append posting-style
+ `((,header "*")))))
+ ))
+ nndiary-headers)
+ (gnus-group-set-parameter group 'posting-style posting-style)
+ ;; Summary line format:
+ (unless (gnus-group-get-parameter group 'gnus-summary-line-format t)
+ (gnus-group-set-parameter group 'gnus-summary-line-format
+ `(,gnus-diary-summary-line-format)))
+ ;; Sorting by schedule:
+ (unless (gnus-group-get-parameter group 'gnus-article-sort-functions)
+ (gnus-group-set-parameter group 'gnus-article-sort-functions
+ '((append gnus-article-sort-functions
+ (list
+ 'gnus-article-sort-by-schedule)))))
+ (unless (gnus-group-get-parameter group 'gnus-thread-sort-functions)
+ (gnus-group-set-parameter group 'gnus-thread-sort-functions
+ '((append gnus-thread-sort-functions
+ (list
+ 'gnus-thread-sort-by-schedule)))))
+ ))
+
+;; Called when a group is subscribed. This is needed because groups created
+;; because of mail splitting are *not* created with the backend function.
+;; Thus, `nndiary-request-create-group-hooks' is inoperative.
+(defun gnus-diary-maybe-update-group-parameters (group)
+ (when (eq (car (gnus-find-method-for-group group)) 'nndiary)
+ (gnus-diary-update-group-parameters group)))
+
+(add-hook 'nndiary-request-create-group-hooks
+ 'gnus-diary-update-group-parameters)
+;; Now that we have `gnus-subscribe-newsgroup-hooks', this is not needed
+;; anymore. Maybe I should remove this completely.
+(add-hook 'nndiary-request-update-info-hooks
+ 'gnus-diary-update-group-parameters)
+(add-hook 'gnus-subscribe-newsgroup-hooks
+ 'gnus-diary-maybe-update-group-parameters)
+
+
+;; Diary Message Checking ===================================================
+
+(defvar gnus-diary-header-value-history nil
+ ;; History variable for header value prompting
+ )
+
+(defun gnus-diary-narrow-to-headers ()
+ "Narrow the current buffer to the header part.
+Point is left at the beginning of the region.
+The buffer is assumed to contain a message, but the format is unknown."
+ (cond ((eq major-mode 'message-mode)
+ (message-narrow-to-headers))
+ (t
+ (goto-char (point-min))
+ (when (search-forward "\n\n" nil t)
+ (narrow-to-region (point-min) (- (point) 1))
+ (goto-char (point-min))))
+ ))
+
+(defun gnus-diary-add-header (str)
+ "Add a header to the current buffer.
+The buffer is assumed to contain a message, but the format is unknown."
+ (cond ((eq major-mode 'message-mode)
+ (message-add-header str))
+ (t
+ (save-restriction
+ (gnus-diary-narrow-to-headers)
+ (goto-char (point-max))
+ (if (string-match "\n$" str)
+ (insert str)
+ (insert str ?\n))))
+ ))
+
+(defun gnus-diary-check-message (arg)
+ "Ensure that the current message is a valid for NNDiary.
+This function checks that all NNDiary required headers are present and
+valid, and prompts for values / correction otherwise.
+
+If ARG (or prefix) is non-nil, force prompting for all fields."
+ (interactive "P")
+ (save-excursion
+ (mapcar
+ (lambda (head)
+ (let ((header (concat "X-Diary-" (car head)))
+ (ask arg)
+ value invalid)
+ ;; First, try to find the header, and checks for validity:
+ (save-restriction
+ (gnus-diary-narrow-to-headers)
+ (when (re-search-forward (concat "^" header ":") nil t)
+ (unless (eq (char-after) ? )
+ (insert " "))
+ (setq value (buffer-substring (point) (gnus-point-at-eol)))
+ (and (string-match "[ \t]*\\([^ \t]+\\)[ \t]*" value)
+ (setq value (match-string 1 value)))
+ (condition-case ()
+ (nndiary-parse-schedule-value value
+ (nth 1 head) (nth 2 head))
+ (t
+ (setq invalid t)))
+ ;; #### NOTE: this (along with the `gnus-diary-add-header'
+ ;; function) could be rewritten in a better way, in particular
+ ;; not to blindly remove an already present header and reinsert
+ ;; it somewhere else afterwards.
+ (when (or ask invalid)
+ (gnus-diary-kill-entire-line))
+ ))
+ ;; Now, loop until a valid value is provided:
+ (while (or ask (not value) invalid)
+ (let ((prompt (concat (and invalid
+ (prog1 "(current value invalid) "
+ (beep)))
+ header ": ")))
+ (setq value
+ (if (listp (nth 1 head))
+ (completing-read prompt (cons '("*" nil) (nth 1 head))
+ nil t value
+ gnus-diary-header-value-history)
+ (read-string prompt value
+ gnus-diary-header-value-history))))
+ (setq ask nil)
+ (setq invalid nil)
+ (condition-case ()
+ (nndiary-parse-schedule-value value
+ (nth 1 head) (nth 2 head))
+ (t
+ (setq invalid t))))
+ (gnus-diary-add-header (concat header ": " value))
+ ))
+ nndiary-headers)
+ ))
+
+(add-hook 'nndiary-request-accept-article-hooks
+ (lambda () (gnus-diary-check-message nil)))
+
+(define-key message-mode-map "\C-cDc" 'gnus-diary-check-message)
+(define-key gnus-article-edit-mode-map "\C-cDc" 'gnus-diary-check-message)
+
+
+;; The end ==================================================================
+
+(defun gnus-diary-version ()
+ "Current Diary backend version."
+ (interactive)
+ (message "NNDiary version %s" nndiary-version))
+
+(define-key message-mode-map "\C-cDv" 'gnus-diary-version)
+(define-key gnus-article-edit-mode-map "\C-cDv" 'gnus-diary-version)
+
+
+(provide 'gnus-diary)
+
+;;; gnus-diary.el ends here
;;; gnus-draft.el --- draft message support for Gnus
-;; Copyright (C) 1997, 1998, 1999, 2000
+;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
(defun gnus-draft-edit-message ()
"Enter a mail/post buffer to edit and send the draft."
(interactive)
- (let ((article (gnus-summary-article-number)))
+ (let ((article (gnus-summary-article-number))
+ (group gnus-newsgroup-name))
(gnus-summary-mark-as-read article gnus-canceled-mark)
- (gnus-draft-setup article gnus-newsgroup-name t)
+ (gnus-draft-setup article group t)
(set-buffer-modified-p t)
+ (save-excursion
+ (save-restriction
+ (message-narrow-to-headers)
+ (message-remove-header "date")))
(save-buffer)
(let ((gnus-verbose-backends nil))
- (gnus-request-expire-articles (list article) gnus-newsgroup-name t))
+ (gnus-request-expire-articles (list article) group t))
(push
`((lambda ()
(when (gnus-buffer-exists-p ,gnus-summary-buffer)
(while (setq article (pop articles))
(gnus-summary-remove-process-mark article)
(unless (memq article gnus-newsgroup-unsendable)
- (let ((message-sending-message
- (format "Sending message %d of %d..."
+ (let ((message-sending-message
+ (format "Sending message %d of %d..."
(- total (length articles)) total)))
(gnus-draft-send article gnus-newsgroup-name t))
(gnus-summary-mark-article article gnus-canceled-mark)))))
"Send message ARTICLE."
(let ((message-syntax-checks (if interactive nil
'dont-check-for-anything-just-trust-me))
- (message-inhibit-body-encoding (or (not group)
+ (message-inhibit-body-encoding (or (not group)
(equal group "nndraft:queue")
message-inhibit-body-encoding))
(message-send-hook (and group (not (equal group "nndraft:queue"))
(gnus-uu-mark-buffer)
(gnus-draft-send-message))
-(defun gnus-group-send-drafts ()
+(defun gnus-group-send-queue ()
"Send all sendable articles from the queue group."
(interactive)
(gnus-activate-group "nndraft:queue")
article)
(while (setq article (pop articles))
(unless (memq article unsendable)
- (let ((message-sending-message
- (format "Sending message %d of %d..."
+ (let ((message-sending-message
+ (format "Sending message %d of %d..."
(- total (length articles)) total)))
(gnus-draft-send article)))))))
(forward-line 1)
(setq ga (message-fetch-field gnus-draft-meta-information-header))
(message-set-auto-save-file-name))))
+ (gnus-backlog-remove-article group narticle)
(when (and ga
(ignore-errors (setq ga (car (read-from-string ga)))))
+ (setq gnus-newsgroup-name
+ (if (equal (car ga) "") nil (car ga)))
(setq message-post-method
`(lambda (arg)
(gnus-post-method arg ,(car ga))))
- (message-add-action
- `(gnus-add-mark ,(car ga) 'replied ,(cadr ga))
- 'send)))))
+ (unless (equal (cadr ga) "")
+ (message-add-action
+ `(progn
+ (gnus-add-mark ,(car ga) 'replied ,(cadr ga))
+ (gnus-request-set-mark ,(car ga) (list (list (list ,(cadr ga))
+ 'add '(reply)))))
+ 'send))))))
(defun gnus-draft-article-sendable-p (article)
"Say whether ARTICLE is sendable."
;;; gnus-eform.el --- a mode for editing forms for Gnus
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
"Update changes and kill the current buffer."
(interactive)
(goto-char (point-min))
- (let ((form (read (current-buffer)))
+ (let ((form (condition-case nil
+ (read (current-buffer))
+ (end-of-file nil)))
(func gnus-edit-form-done-function))
(gnus-edit-form-exit)
(funcall func form)))
valstr)))
(eval-and-compile
+ (defalias 'gnus-char-width
+ (if (fboundp 'char-width)
+ 'char-width
+ (lambda (ch) 1)))) ;; A simple hack.
+
+(eval-and-compile
(if (featurep 'xemacs)
(gnus-xmas-define)
(defvar gnus-mouse-face-prop 'mouse-face
(append nnheader-file-name-translation-alist
(mapcar (lambda (c) (cons c ?_))
'(?: ?* ?\" ?< ?> ??))
- '((?+ . ?-))))))))
+ (if (string-match "windows-nt\\|cygwin32"
+ (symbol-name system-type))
+ nil
+ '((?+ . ?-)))))))))
(defvar gnus-tmp-unread)
(defvar gnus-tmp-replied)
"Non-nil means the compface program supports the -X option.
That produces XBM output.")
-(defun gnus-article-display-xface (beg end &optional buffer)
- "Display an XFace header from between BEG and END in BUFFER.
+(defun gnus-article-display-xface (data)
+ "Display the XFace header FACE in the current buffer.
Requires support for images in your Emacs and the external programs
`uncompface', and `icontopbm'. On a GNU/Linux system these
might be in packages with names like `compface' or `faces-xface' and
(make-ring gnus-article-xface-ring-size)))
(save-excursion
(let* ((cur (current-buffer))
- (data (if buffer
- (with-current-buffer buffer
- (buffer-substring beg end))
- (buffer-substring beg end)))
(image (cdr-safe (assoc data (ring-elements
gnus-article-xface-ring-internal))))
default-enable-multibyte-characters)
(when image
(goto-char (point-min))
(re-search-forward "^From:" nil 'move)
+ (while (get-text-property (point) 'display)
+ (goto-char (next-single-property-change (point) 'display)))
+ (gnus-add-wash-type 'xface)
+ (gnus-add-image 'xface image)
(insert-image image))))))
+;;; Image functions.
+
+(defun gnus-image-type-available-p (type)
+ (and (fboundp 'image-type-available-p)
+ (image-type-available-p type)))
+
+(defun gnus-create-image (file)
+ (create-image file))
+
+(defun gnus-put-image (glyph &optional string)
+ (insert-image glyph string))
+
+(defun gnus-remove-image (image)
+ (dolist (position (gnus-text-with-property 'display))
+ (when (equal (get-text-property position 'display) image)
+ (put-text-property position (1+ position) 'display nil))))
+
(provide 'gnus-ems)
;;; gnus-ems.el ends here
;;; gnus-gl.el --- an interface to GroupLens for Gnus
-;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
;; Author: Brad Miller <bmiller@cs.umn.edu>
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defvar gnus-summary-grouplens-line-format
- "%U\%R\%z%l%I\%(%[%4L: %-20,20n%]%) %s\n"
+ "%U\%R\%z%l%I\%(%[%4L: %-23,23n%]%) %s\n"
"*The line format spec in summary GroupLens mode buffers.")
(defvar grouplens-pseudonym ""
;; Return an empty string
""
(let* ((rate-string (make-string 12 ?\ ))
- (mid (mail-header-id header))
- (hashent (gnus-gethash mid grouplens-current-hashtable))
- (pred (or (nth 0 hashent) 0))
- (low (nth 1 hashent))
- (high (nth 2 hashent)))
+ (mid (mail-header-id header))
+ (hashent (gnus-gethash mid grouplens-current-hashtable))
+ (pred (or (nth 0 hashent) 0))
+ (low (nth 1 hashent))
+ (high (nth 2 hashent)))
;; Init rate-string
(aset rate-string 0 ?|)
(aset rate-string 11 ?|)
(defun bbb-build-rate-command (rate-alist)
(concat "putratings " grouplens-bbb-token " " grouplens-current-group " \r\n"
- (mapconcat '(lambda (this) ; form (mid . (score . time))
- (concat (car this)
- " :rating=" (cadr this) ".00"
- " :time=" (cddr this)))
+ (mapconcat (lambda (this) ; form (mid . (score . time))
+ (concat (car this)
+ " :rating=" (cadr this) ".00"
+ " :time=" (cddr this)))
rate-alist "\r\n")
"\r\n.\r\n"))
;;; gnus-group.el --- group mode commands for Gnus
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
list."
:group 'gnus-group-listing
:link '(custom-manual "(gnus)Sorting Groups")
- :type '(radio (function-item gnus-group-sort-by-alphabet)
- (function-item gnus-group-sort-by-real-name)
- (function-item gnus-group-sort-by-unread)
- (function-item gnus-group-sort-by-level)
- (function-item gnus-group-sort-by-score)
- (function-item gnus-group-sort-by-method)
- (function-item gnus-group-sort-by-server)
- (function-item gnus-group-sort-by-rank)
- (function :tag "other" nil)))
-
-(defcustom gnus-group-line-format "%M\%S\%p\%P\%5y: %(%g%)%l\n"
+ :type '(repeat :value-to-internal (lambda (widget value)
+ (if (listp value) value (list value)))
+ :match (lambda (widget value)
+ (or (symbolp value)
+ (widget-editable-list-match widget value)))
+ (choice (function-item gnus-group-sort-by-alphabet)
+ (function-item gnus-group-sort-by-real-name)
+ (function-item gnus-group-sort-by-unread)
+ (function-item gnus-group-sort-by-level)
+ (function-item gnus-group-sort-by-score)
+ (function-item gnus-group-sort-by-method)
+ (function-item gnus-group-sort-by-server)
+ (function-item gnus-group-sort-by-rank)
+ (function :tag "other" nil))))
+
+(defcustom gnus-group-line-format "%M\%S\%p\%P\%5y: %(%g%)%l %O\n"
"*Format of group lines.
It works along the same lines as a normal formatting string,
with some simple extensions.
%y Number of unread, unticked articles (integer)
%G Group name (string)
%g Qualified group name (string)
+%c Short (collapsed) group name. See `gnus-group-uncollapsed-levels'.
%D Group description (string)
%s Select method (string)
%o Moderated group (char, \"m\")
:group 'gnus-group-visual
:type 'string)
-(defcustom gnus-group-mode-hook nil
- "Hook for Gnus group mode."
- :group 'gnus-group-various
- :options '(gnus-topic-mode)
- :type 'hook)
-
;; Extracted from gnus-xmas-redefine in order to preserve user settings
(when (featurep 'xemacs)
(add-hook 'gnus-group-mode-hook 'gnus-xmas-group-menu-add)
(sexp :tag "Method"))))
(defcustom gnus-group-highlight
- '(;; News.
- ((and (= unread 0) (not mailp) (eq level 1)) .
+ '(;; Mail.
+ ((and mailp (= unread 0) (eq level 1)) .
+ gnus-group-mail-1-empty-face)
+ ((and mailp (eq level 1)) .
+ gnus-group-mail-1-face)
+ ((and mailp (= unread 0) (eq level 2)) .
+ gnus-group-mail-2-empty-face)
+ ((and mailp (eq level 2)) .
+ gnus-group-mail-2-face)
+ ((and mailp (= unread 0) (eq level 3)) .
+ gnus-group-mail-3-empty-face)
+ ((and mailp (eq level 3)) .
+ gnus-group-mail-3-face)
+ ((and mailp (= unread 0)) .
+ gnus-group-mail-low-empty-face)
+ ((and mailp) .
+ gnus-group-mail-low-face)
+ ;; News.
+ ((and (= unread 0) (eq level 1)) .
gnus-group-news-1-empty-face)
- ((and (not mailp) (eq level 1)) .
+ ((and (eq level 1)) .
gnus-group-news-1-face)
- ((and (= unread 0) (not mailp) (eq level 2)) .
+ ((and (= unread 0) (eq level 2)) .
gnus-group-news-2-empty-face)
- ((and (not mailp) (eq level 2)) .
+ ((and (eq level 2)) .
gnus-group-news-2-face)
- ((and (= unread 0) (not mailp) (eq level 3)) .
+ ((and (= unread 0) (eq level 3)) .
gnus-group-news-3-empty-face)
- ((and (not mailp) (eq level 3)) .
+ ((and (eq level 3)) .
gnus-group-news-3-face)
- ((and (= unread 0) (not mailp) (eq level 4)) .
+ ((and (= unread 0) (eq level 4)) .
gnus-group-news-4-empty-face)
- ((and (not mailp) (eq level 4)) .
+ ((and (eq level 4)) .
gnus-group-news-4-face)
- ((and (= unread 0) (not mailp) (eq level 5)) .
+ ((and (= unread 0) (eq level 5)) .
gnus-group-news-5-empty-face)
- ((and (not mailp) (eq level 5)) .
+ ((and (eq level 5)) .
gnus-group-news-5-face)
- ((and (= unread 0) (not mailp) (eq level 6)) .
+ ((and (= unread 0) (eq level 6)) .
gnus-group-news-6-empty-face)
- ((and (not mailp) (eq level 6)) .
+ ((and (eq level 6)) .
gnus-group-news-6-face)
- ((and (= unread 0) (not mailp)) .
+ ((and (= unread 0)) .
gnus-group-news-low-empty-face)
- ((and (not mailp)) .
- gnus-group-news-low-face)
- ;; Mail.
- ((and (= unread 0) (eq level 1)) .
- gnus-group-mail-1-empty-face)
- ((eq level 1) .
- gnus-group-mail-1-face)
- ((and (= unread 0) (eq level 2)) .
- gnus-group-mail-2-empty-face)
- ((eq level 2) .
- gnus-group-mail-2-face)
- ((and (= unread 0) (eq level 3)) .
- gnus-group-mail-3-empty-face)
- ((eq level 3) .
- gnus-group-mail-3-face)
- ((= unread 0) .
- gnus-group-mail-low-empty-face)
(t .
- gnus-group-mail-low-face))
+ gnus-group-news-low-face))
"*Controls the highlighting of group buffer lines.
Below is a list of `Form'/`Face' pairs. When deciding how a a
:type '(repeat (cons (sexp :tag "Form") file)))
(defcustom gnus-group-name-charset-method-alist nil
- "*Alist of method and the charset for group names.
+ "Alist of method and the charset for group names.
For example:
- (((nntp \"news.com.cn\") . cn-gb-2312))
-"
+ (((nntp \"news.com.cn\") . cn-gb-2312))"
:version "21.1"
:group 'gnus-charset
:type '(repeat (cons (sexp :tag "Method") (symbol :tag "Charset"))))
-(defcustom gnus-group-name-charset-group-alist nil
- "*Alist of group regexp and the charset for group names.
+(defcustom gnus-group-name-charset-group-alist
+ (if (or (and (fboundp 'find-coding-system) (find-coding-system 'utf-8))
+ (and (fboundp 'coding-system-p) (coding-system-p 'utf-8)))
+ '((".*" . utf-8))
+ nil)
+ "Alist of group regexp and the charset for group names.
For example:
- ((\"\\.com\\.cn:\" . cn-gb-2312))
-"
+ ((\"\\.com\\.cn:\" . cn-gb-2312))"
:group 'gnus-charset
:type '(repeat (cons (regexp :tag "Group") (symbol :tag "Charset"))))
in the minibuffer prompt."
:group 'gnus-group-various
:type '(choice (string :tag "Prompt string")
- (const :tag "Empty" nil)))
+ (const :tag "Empty" nil)))
(defvar gnus-group-listing-limit 1000
"*A limit of the number of groups when listing.
"l" gnus-group-list-groups
"L" gnus-group-list-all-groups
"m" gnus-group-mail
+ "i" gnus-group-news
"g" gnus-group-get-new-news
"\M-g" gnus-group-get-new-news-this-group
"R" gnus-group-restart
"r" gnus-group-mark-regexp
"U" gnus-group-unmark-all-groups)
+ (gnus-define-keys (gnus-group-sieve-map "D" gnus-group-mode-map)
+ "u" gnus-sieve-update
+ "g" gnus-sieve-generate)
+
(gnus-define-keys (gnus-group-group-map "G" gnus-group-mode-map)
"d" gnus-group-make-directory-group
"h" gnus-group-make-help-group
["Jump to group" gnus-group-jump-to-group t]
["First unread group" gnus-group-first-unread-group t]
["Best unread group" gnus-group-best-unread-group t])
+ ("Sieve"
+ ["Generate" gnus-sieve-generate t]
+ ["Generate and update" gnus-sieve-update t])
["Delete bogus groups" gnus-group-check-bogus-groups t]
["Find new newsgroups" gnus-group-find-new-groups t]
["Transpose" gnus-group-transpose-groups
(easy-menu-define
gnus-group-misc-menu gnus-group-mode-map ""
- `("Misc"
+ `("Gnus"
("SOUP"
["Pack replies" nnsoup-pack-replies (fboundp 'nnsoup-request-group)]
["Send replies" gnus-soup-send-replies
["Save areas" gnus-soup-save-areas (fboundp 'gnus-soup-pack-packet)]
["Brew SOUP" gnus-group-brew-soup (fboundp 'gnus-soup-pack-packet)])
["Send a mail" gnus-group-mail t]
- ["Post an article..." gnus-group-post-news t]
+ ["Send a message (mail or news)" gnus-group-post-news t]
+ ["Create a local message" gnus-group-news t]
["Check for new news" gnus-group-get-new-news
,@(if (featurep 'xemacs) '(t)
'(:help "Get newly arrived articles"))
]
+ ["Send queued messages" gnus-delay-send-queue
+ ,@(if (featurep 'xemacs) '(t)
+ '(:help "Send all messages that are scheduled to be sent now"))
+ ]
["Activate all groups" gnus-activate-all-groups t]
["Restart Gnus" gnus-group-restart t]
["Read init file" gnus-group-read-init-file t]
(defun gnus-update-group-mark-positions ()
(save-excursion
(let ((gnus-process-mark ?\200)
+ (gnus-group-update-hook nil)
(gnus-group-marked '("dummy.group"))
(gnus-active-hashtb (make-vector 10 0))
(topic ""))
(when gnus-carpal
(gnus-carpal-setup-buffer 'group))))
-(defsubst gnus-group-name-charset (method group)
+(defun gnus-group-name-charset (method group)
(if (null method)
(setq method (gnus-find-method-for-group group)))
(let ((item (assoc method gnus-group-name-charset-method-alist))
result (cdr item))))
result)))
-(defsubst gnus-group-name-decode (string charset)
- (if (and string charset (featurep 'mule))
+(defun gnus-group-name-decode (string charset)
+ (if (and string charset (featurep 'mule)
+ (not (mm-multibyte-string-p string)))
(mm-decode-coding-string string charset)
string))
(point)
(prog1 (1+ (point))
;; Insert the text.
- (eval gnus-group-line-format-spec))
+ (let ((gnus-tmp-group (gnus-group-name-decode
+ gnus-tmp-group group-name-charset)))
+ (eval gnus-group-line-format-spec)))
`(gnus-group ,(gnus-intern-safe gnus-tmp-group gnus-active-hashtb)
gnus-unread ,(if (numberp number)
(string-to-int gnus-tmp-number-of-unread)
(info (nth 2 entry))
(method (gnus-server-get-method group (gnus-info-method info)))
(marked (gnus-info-marks info))
- (mailp (memq 'mail (assoc (symbol-name
- (car (or method gnus-select-method)))
- gnus-valid-select-methods)))
+ (mailp (apply 'append
+ (mapcar
+ (lambda (x)
+ (memq x (assoc (symbol-name
+ (car (or method gnus-select-method)))
+ gnus-valid-select-methods)))
+ '(mail post-mail))))
(level (or (gnus-info-level info) gnus-level-killed))
(score (or (gnus-info-score info) 0))
(ticked (gnus-range-length (cdr (assq 'tick marked))))
(defun gnus-group-select-group (&optional all)
"Select this newsgroup.
No article is selected automatically.
+If the group is opened, just switch the summary buffer.
If ALL is non-nil, already read articles become readable.
If ALL is a number, fetch this number of articles."
(interactive "P")
(,(intern (format "%s-address" (car method))) ,(cadr method))
,@(cddr method)))
(let ((group (if (gnus-group-foreign-p group) group
- (gnus-group-prefixed-name group method))))
+ (gnus-group-prefixed-name (gnus-group-real-name group)
+ method))))
(gnus-sethash
group
`(-1 nil (,group
(list (gnus-group-group-name)
current-prefix-arg))
(unless group
- (error "No group to rename"))
+ (error "No group to delete"))
(unless (gnus-check-backend-function 'request-delete-group group)
(error "This backend does not support group deletion"))
(prog1
(t "group info"))
(gnus-group-decoded-name group))
`(lambda (form)
- (gnus-group-edit-group-done ',part ,group form)))))
+ (gnus-group-edit-group-done ',part ,group form)))
+ (local-set-key
+ "\C-c\C-i"
+ (gnus-create-info-command
+ (cond
+ ((eq part 'method)
+ "(gnus)Select Methods")
+ ((eq part 'params)
+ "(gnus)Group Parameters")
+ (t
+ "(gnus)Group Info"))))))
(defun gnus-group-edit-group-method (group)
"Edit the select method of GROUP."
(setcar entry (eval (cadar entry)))))
(gnus-group-make-group group method))
-(defun gnus-group-make-help-group ()
- "Create the Gnus documentation group."
+(defun gnus-group-make-help-group (&optional noerror)
+ "Create the Gnus documentation group.
+Optional argument NOERROR modifies the behavior of this function when the
+group already exists:
+- if not given, and error is signaled,
+- if t, stay silent,
+- if anything else, just print a message."
(interactive)
(let ((name (gnus-group-prefixed-name "gnus-help" '(nndoc "gnus-help")))
(file (nnheader-find-etc-directory "gnus-tut.txt" t)))
- (when (gnus-gethash name gnus-newsrc-hashtb)
- (error "Documentation group already exists"))
- (if (not file)
- (gnus-message 1 "Couldn't find doc group")
- (gnus-group-make-group
- (gnus-group-real-name name)
- (list 'nndoc "gnus-help"
- (list 'nndoc-address file)
- (list 'nndoc-article-type 'mbox)))))
+ (if (gnus-gethash name gnus-newsrc-hashtb)
+ (cond ((eq noerror nil)
+ (error "Documentation group already exists"))
+ ((eq noerror t)
+ ;; stay silent
+ )
+ (t
+ (gnus-message 1 "Documentation group already exists")))
+ ;; else:
+ (if (not file)
+ (gnus-message 1 "Couldn't find doc group")
+ (gnus-group-make-group
+ (gnus-group-real-name name)
+ (list 'nndoc "gnus-help"
+ (list 'nndoc-address file)
+ (list 'nndoc-article-type 'mbox))))
+ ))
(gnus-group-position-point))
(defun gnus-group-make-doc-group (file type)
(interactive (list gnus-group-sort-function current-prefix-arg))
(funcall gnus-group-sort-alist-function
(gnus-make-sort-function func) reverse)
+ (gnus-group-unmark-all-groups)
(gnus-group-list-groups)
(gnus-dribble-touch))
(let ((groups (gnus-group-process-prefix n)))
(funcall gnus-group-sort-selected-function
groups (gnus-make-sort-function func) reverse)
- (gnus-group-list-groups)))
+ (gnus-group-unmark-all-groups)
+ (gnus-group-list-groups)
+ (gnus-dribble-touch)))
(defun gnus-group-sort-selected-flat (groups func reverse)
(let (entries infos)
(defun gnus-group-sort-by-server (info1 info2)
"Sort alphabetically by server name."
- (string< (gnus-method-to-server-name
+ (string< (gnus-method-to-full-server-name
(gnus-find-method-for-group
(gnus-info-group info1) info1))
- (gnus-method-to-server-name
+ (gnus-method-to-full-server-name
(gnus-find-method-for-group
(gnus-info-group info2) info2))))
(defun gnus-info-clear-data (info)
"Clear all marks and read ranges from INFO."
- (let ((group (gnus-info-group info)))
+ (let ((group (gnus-info-group info))
+ action)
+ (dolist (el (gnus-info-marks info))
+ (push `(,(cdr el) add (,(car el))) action))
+ (push `(,(gnus-info-read info) add (read)) action)
(gnus-undo-register
`(progn
+ (gnus-request-set-mark ,group ',action)
(gnus-info-set-marks ',info ',(gnus-info-marks info) t)
(gnus-info-set-read ',info ',(gnus-info-read info))
(when (gnus-group-goto-group ,group)
+ (gnus-get-unread-articles-in-group ',info ',(gnus-active group) t)
(gnus-group-update-group-line))))
+ (setq action (mapcar (lambda (el) (list (nth 0 el) 'del (nth 2 el)))
+ action))
+ (gnus-request-set-mark group action)
(gnus-info-set-read info nil)
(when (gnus-info-marks info)
(gnus-info-set-marks info nil))))
The return value is the number of articles that were marked as read,
or nil if no action could be taken."
(let* ((entry (gnus-gethash group gnus-newsrc-hashtb))
- (num (car entry)))
+ (num (car entry))
+ (marks (nth 3 (nth 2 entry)))
+ (unread (gnus-list-of-unread-articles group)))
;; Remove entries for this group.
(nnmail-purge-split-history (gnus-group-real-name group))
;; Do the updating only if the newsgroup isn't killed.
(if (not (numberp (car entry)))
(gnus-message 1 "Can't catch up %s; non-active group" group)
+ (gnus-update-read-articles group nil)
+ (when all
+ ;; Nix out the lists of marks and dormants.
+ (gnus-request-set-mark group (list (list (cdr (assq 'tick marks))
+ 'del '(tick))
+ (list (cdr (assq 'dormant marks))
+ 'del '(dormant))))
+ (setq unread (gnus-uncompress-range
+ (gnus-range-add (gnus-range-add
+ unread (cdr (assq 'dormant marks)))
+ (cdr (assq 'tick marks)))))
+ (gnus-add-marked-articles group 'tick nil nil 'force)
+ (gnus-add-marked-articles group 'dormant nil nil 'force))
;; Do auto-expirable marks if that's required.
(when (gnus-group-auto-expirable-p group)
- (gnus-add-marked-articles
- group 'expire (gnus-list-of-unread-articles group))
- (when all
- (let ((marks (nth 3 (nth 2 entry))))
- (gnus-add-marked-articles
- group 'expire (gnus-uncompress-range (cdr (assq 'tick marks))))
- (gnus-add-marked-articles
- group 'expire (gnus-uncompress-range (cdr (assq 'tick marks)))))))
- (when entry
- (gnus-update-read-articles group nil)
- ;; Also nix out the lists of marks and dormants.
- (when all
- (gnus-add-marked-articles group 'tick nil nil 'force)
- (gnus-add-marked-articles group 'dormant nil nil 'force))
- (let ((gnus-newsgroup-name group))
- (gnus-run-hooks 'gnus-group-catchup-group-hook))
- num))))
+ (gnus-add-marked-articles group 'expire unread)
+ (gnus-request-set-mark group (list (list unread 'add '(expire)))))
+ (let ((gnus-newsgroup-name group))
+ (gnus-run-hooks 'gnus-group-catchup-group-hook))
+ num)))
(defun gnus-group-expire-articles (&optional n)
"Expire all expirable articles in the current newsgroup."
(defun gnus-group-find-new-groups (&optional arg)
"Search for new groups and add them.
-Each new group will be treated with `gnus-subscribe-newsgroup-method.'
+Each new group will be treated with `gnus-subscribe-newsgroup-method'.
With 1 C-u, use the `ask-server' method to query the server for new
groups.
With 2 C-u's, use most complete method possible to query the server
"Return the offset in seconds from the timestamp for GROUP to the current time, as a floating point number."
(let* ((time (or (gnus-group-timestamp group)
(list 0 0)))
- (delta (subtract-time (current-time) time)))
+ (delta (subtract-time (current-time) time)))
(+ (* (nth 0 delta) 65536.0)
(nth 1 delta))))
(gnus-group-list-plus args)))
(defun gnus-group-mark-article-read (group article)
- "Mark ARTICLE read."
+ "Mark ARTICLE read."
(gnus-activate-group group)
(let ((buffer (gnus-summary-buffer-name group))
(mark gnus-read-mark))
"Check whether the connection to METHOD is down.
If METHOD is nil, use `gnus-select-method'.
If it is down, start it up (again)."
- (let ((method (or method gnus-select-method)))
+ (let ((method (or method gnus-select-method))
+ result)
;; Transform virtual server names into select methods.
(when (stringp method)
(setq method (gnus-server-to-method method)))
(gnus-run-hooks 'gnus-open-server-hook)
(prog1
(condition-case ()
- (gnus-open-server method)
+ (setq result (gnus-open-server method))
(quit (message "Quit gnus-check-server")
nil))
(unless silent
- (message ""))))))
+ (gnus-message 5 "Opening %s server%s...%s" (car method)
+ (if (equal (nth 1 method) "") ""
+ (format " on %s" (nth 1 method)))
+ (if result "done" "failed")))))))
(defun gnus-get-function (method function &optional noerror)
"Return a function symbol based on METHOD and FUNCTION."
nil)
;; Open the server.
(let ((result
- (funcall (gnus-get-function gnus-command-method 'open-server)
- (nth 1 gnus-command-method)
- (nthcdr 2 gnus-command-method))))
+ (condition-case ()
+ (funcall (gnus-get-function gnus-command-method 'open-server)
+ (nth 1 gnus-command-method)
+ (nthcdr 2 gnus-command-method))
+ (quit
+ (message "Quit trying to open server")
+ nil))))
;; If this hasn't been opened before, we add it to the list.
(unless elem
(setq elem (list gnus-command-method nil)
;;; gnus-kill.el --- kill commands for Gnus
-;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
(defun gnus-apply-kill-file-unless-scored ()
"Apply .KILL file, unless a .SCORE file for the same newsgroup exists."
(cond ((file-exists-p (gnus-score-file-name gnus-newsgroup-name))
- ;; Ignores global KILL.
- (when (file-exists-p (gnus-newsgroup-kill-file gnus-newsgroup-name))
+ ;; Ignores global KILL.
+ (when (file-exists-p (gnus-newsgroup-kill-file gnus-newsgroup-name))
(gnus-message 3 "Note: Ignoring %s.KILL; preferring .SCORE"
gnus-newsgroup-name))
- 0)
- ((or (file-exists-p (gnus-newsgroup-kill-file nil))
- (file-exists-p (gnus-newsgroup-kill-file gnus-newsgroup-name)))
- (gnus-apply-kill-file-internal))
- (t
- 0)))
+ 0)
+ ((or (file-exists-p (gnus-newsgroup-kill-file nil))
+ (file-exists-p (gnus-newsgroup-kill-file gnus-newsgroup-name)))
+ (gnus-apply-kill-file-internal))
+ (t
+ 0)))
(defun gnus-apply-kill-file-internal ()
"Apply a kill file to the current newsgroup.
gnus-newsgroup-kill-headers))
(setq headers (cdr headers))))
(setq files nil))
- (setq files (cdr files)))))
+ (setq files (cdr files)))))
(if (not gnus-newsgroup-kill-headers)
()
(save-window-excursion
marked as read or ticked are ignored."
(save-excursion
(let ((killed-no 0)
- function article header)
+ function article header extras)
(cond
;; Search body.
((or (null field)
(string-equal field ""))
(setq function nil))
;; Get access function of header field.
- ((fboundp
- (setq function
- (intern-soft
- (concat "mail-header-" (downcase field)))))
- (setq function `(lambda (h) (,function h))))
+ ((cond ((fboundp
+ (setq function
+ (intern-soft
+ (concat "mail-header-" (downcase field)))))
+ (setq function `(lambda (h) (,function h))))
+ ((when (setq extras
+ (member (downcase field)
+ (mapcar (lambda (header)
+ (downcase (symbol-name header)))
+ gnus-extra-headers)))
+ (setq function
+ `(lambda (h)
+ (gnus-extra-header
+ (quote ,(nth (- (length gnus-extra-headers)
+ (length extras))
+ gnus-extra-headers))
+ h)))))))
;; Signal error.
(t
(error "Unknown header field: \"%s\"" field)))
;;; gnus-logic.el --- advanced scoring code for Gnus
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
(provide 'gnus-logic)
-;;; gnus-logic.el ends here.
+;;; gnus-logic.el ends here
;;; gnus-ml.el --- Mailing list minor mode for Gnus
-;; Copyright (C) 2000 Free Software Foundation, Inc.
+;; Copyright (C) 2000, 2001 Free Software Foundation, Inc.
;; Author: Julien Gilles <jgilles@free.fr>
;; Keywords: news
;;;###autoload
(defun turn-on-gnus-mailing-list-mode ()
- (when (gnus-group-get-parameter gnus-newsgroup-name 'to-list)
+ (when (gnus-group-find-parameter gnus-newsgroup-name 'to-list)
(gnus-mailing-list-mode 1)))
;;;###autoload
"Setup group parameters from List-Post header.
If FORCE is non-nil, replace the old ones."
(interactive "P")
- (let ((list-post
+ (let ((list-post
(with-current-buffer gnus-original-article-buffer
(gnus-fetch-field "list-post"))))
(if list-post
(gnus-message 1 "to-list is non-nil.")
(if (string-match "<mailto:\\([^>]*\\)>" list-post)
(setq list-post (match-string 1 list-post)))
- (gnus-group-add-parameter gnus-newsgroup-name
+ (gnus-group-add-parameter gnus-newsgroup-name
(cons 'to-list list-post))
(gnus-mailing-list-mode 1))
(gnus-message 1 "no list-post in this message."))))
(defun gnus-mailing-list-help ()
"Get help from mailing list server."
- (interactive)
- (let ((list-help
+ (interactive)
+ (let ((list-help
(with-current-buffer gnus-original-article-buffer
(gnus-fetch-field "list-help"))))
(cond (list-help (gnus-mailing-list-message list-help))
(defun gnus-mailing-list-subscribe ()
"Subscribe"
(interactive)
- (let ((list-subscribe
+ (let ((list-subscribe
(with-current-buffer gnus-original-article-buffer
(gnus-fetch-field "list-subscribe"))))
(cond (list-subscribe (gnus-mailing-list-message list-subscribe))
(defun gnus-mailing-list-unsubscribe ()
"Unsubscribe"
(interactive)
- (let ((list-unsubscribe
+ (let ((list-unsubscribe
(with-current-buffer gnus-original-article-buffer
(gnus-fetch-field "list-unsubscribe"))))
(cond (list-unsubscribe (gnus-mailing-list-message list-unsubscribe))
(defun gnus-mailing-list-post ()
"Post message (really useful ?)"
(interactive)
- (let ((list-post
+ (let ((list-post
(with-current-buffer gnus-original-article-buffer
(gnus-fetch-field "list-post"))))
(cond (list-post (gnus-mailing-list-message list-post))
(defun gnus-mailing-list-owner ()
"Mail to the owner"
(interactive)
- (let ((list-owner
+ (let ((list-owner
(with-current-buffer gnus-original-article-buffer
(gnus-fetch-field "list-owner"))))
(cond (list-owner (gnus-mailing-list-message list-owner))
"Browse archive"
(interactive)
(require 'browse-url)
- (let ((list-archive
+ (let ((list-archive
(with-current-buffer gnus-original-article-buffer
(gnus-fetch-field "list-archive"))))
- (cond (list-archive
+ (cond (list-archive
(if (string-match "<\\(http:[^>]*\\)>" list-archive)
(browse-url (match-string 1 list-archive))
(browse-url list-archive)))
(subject "None")
(body "")
)
- (cond
+ (cond
((string-match "<mailto:\\([^>]*\\)>" address)
(let ((args (match-string 1 address)))
(cond ; with param
(setq body (match-string 1 param)))
(if (string-match "to=\\([^&]*\\)" param)
(push (match-string 1 param) to))
- ))
+ ))
(t (setq mailto args))))) ; without param
-
+
; other case <http://... to be done.
(t nil))
(gnus-setup-message 'message (message-mail mailto subject))
;;; gnus-mlspl.el --- a group params-based mail splitting mechanism
-;; Copyright (C) 1998, 1999, 2000
+
+;; Copyright (C) 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
;; Author: Alexandre Oliva <oliva@lsd.ic.unicamp.br>
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
+;;; Commentary:
+
+;;; Code:
+
(eval-when-compile (require 'cl))
(require 'gnus)
(require 'gnus-sum)
;;;###autoload
(defun gnus-group-split-fancy
(&optional groups no-crosspost catch-all)
- "Uses information from group parameters in order to split mail. It
-can be embedded into nnmail-split-fancy lists with the SPLIT
+ "Uses information from group parameters in order to split mail.
+It can be embedded into `nnmail-split-fancy' lists with the SPLIT
\(: gnus-group-split-fancy GROUPS NO-CROSSPOST CATCH-ALL\)
\(| (& (any \"\\\\(bar@femail\\\\.com\\\\|.*@femail\\\\.com\\\\)\"
\"mail.bar\")
(any \"\\\\(foo@nowhere\\\\.gov\\\\|foo@localhost\\\\|foo-redist@home\\\\)\"
- - \"bugs-foo\" - \"rambling-foo\" \"mail.foo\"))
+ - \"bugs-foo\" - \"rambling-foo\" \"mail.foo\"))
\"mail.others\")"
(let* ((newsrc (cdr gnus-newsrc-alist))
split)
(list 'any split-regexp)
;; Generate RESTRICTs for SPLIT-EXCLUDEs.
(if (listp split-exclude)
- (let ((seq split-exclude)
- res)
- (while seq
- (push (cons '- (pop seq))
- res))
- (apply #'nconc (nreverse res)))
+ (apply #'append
+ (mapcar (lambda (arg) (list '- arg))
+ split-exclude))
(list '- split-exclude))
(list group-clean))
split)
split))
(provide 'gnus-mlspl)
+
+;;; gnus-mlspl.el ends here
"*Preferred method for posting USENET news.
If this variable is `current' (which is the default), Gnus will use
-the \"current\" select method when posting. If it is nil, Gnus will
-use the native select method when posting.
+the \"current\" select method when posting. If it is `native', Gnus
+will use the native select method when posting.
This method will not be used in mail groups and the like, only in
\"real\" newsgroups.
-If not nil nor `native', the value must be a valid method as discussed
+If not `native' nor `current', the value must be a valid method as discussed
in the documentation of `gnus-select-method'. It can also be a list of
methods. If that is the case, the user will be queried for what select
method to use when posting."
:group 'gnus-group-foreign
- :type `(choice (const nil)
- (const current)
- (const native)
+ :link '(custom-manual "(gnus)Posting Server")
+ :type `(choice (const native)
+ (const current)
(sexp :tag "Methods" ,gnus-select-method)))
-(defvar gnus-outgoing-message-group nil
+(defcustom gnus-outgoing-message-group nil
"*All outgoing messages will be put in this group.
If you want to store all your outgoing mail and articles in the group
\"nnml:archive\", you set this variable to that value. This variable
If you want to have greater control over what group to put each
message in, you can set this variable to a function that checks the
current newsgroup name and then returns a suitable group name (or list
-of names).")
+of names)."
+ :group 'gnus-message
+ :type '(choice (string :tag "Group")
+ (function)))
-(defvar gnus-mailing-list-groups nil
+(defcustom gnus-mailing-list-groups nil
"*Regexp matching groups that are really mailing lists.
This is useful when you're reading a mailing list that has been
gatewayed to a newsgroup, and you want to followup to an article in
-the group.")
+the group."
+ :group 'gnus-message
+ :type 'regexp)
-(defvar gnus-add-to-list nil
- "*If non-nil, add a `to-list' parameter automatically.")
+(defcustom gnus-add-to-list nil
+ "*If non-nil, add a `to-list' parameter automatically."
+ :group 'gnus-message
+ :type 'boolean)
-(defvar gnus-crosspost-complaint
+(defcustom gnus-crosspost-complaint
"Hi,
You posted the article below with the following Newsgroups header:
"
"Format string to be inserted when complaining about crossposts.
The first %s will be replaced by the Newsgroups header;
-the second with the current group name.")
-
-(defvar gnus-message-setup-hook nil
- "Hook run after setting up a message buffer.")
-
-(defvar gnus-bug-create-help-buffer t
- "*Should we create the *Gnus Help Bug* buffer?")
-
-(defvar gnus-posting-styles nil
- "*Alist of styles to use when posting.")
-
-(defvar gnus-inews-mark-gcc-as-read nil
- "If non-nil, automatically mark Gcc articles as read.")
+the second with the current group name."
+ :group 'gnus-message
+ :type 'string)
+
+(defcustom gnus-message-setup-hook nil
+ "Hook run after setting up a message buffer."
+ :group 'gnus-message
+ :type 'hook)
+
+(defcustom gnus-bug-create-help-buffer t
+ "*Should we create the *Gnus Help Bug* buffer?"
+ :group 'gnus-message
+ :type 'boolean)
+
+(defcustom gnus-posting-styles nil
+ "*Alist of styles to use when posting.
+See Info node `(gnus)Posting Styles'."
+ :group 'gnus-message
+ :type '(repeat (cons (choice (regexp)
+ (function)
+ (variable)
+ (sexp))
+ (repeat (list
+ (choice (const signature)
+ (const signature-file)
+ (const organization)
+ (const address)
+ (const name)
+ (const body)
+ (string :tag "Header"))
+ (choice (string)
+ (function)
+ (variable)
+ (sexp)))))))
+
+(defcustom gnus-inews-mark-gcc-as-read nil
+ "If non-nil, automatically mark Gcc articles as read."
+ :group 'gnus-message
+ :type 'boolean)
(defcustom gnus-group-posting-charset-alist
'(("^\\(no\\|fr\\)\\.[^,]*\\(,[ \t\n]*\\(no\\|fr\\)\\.[^,]*\\)*$" iso-8859-1 (iso-8859-1))
(defvar gnus-last-posting-server nil)
(defvar gnus-message-group-art nil)
+(defvar gnus-msg-force-broken-reply-to nil)
+
(defconst gnus-bug-message
"Sending a bug report to the Gnus Towers.
========================================
(gnus-define-keys (gnus-summary-send-map "S" gnus-summary-mode-map)
"p" gnus-summary-post-news
+ "i" gnus-summary-news-other-window
"f" gnus-summary-followup
"F" gnus-summary-followup-with-original
"c" gnus-summary-cancel-article
"m" gnus-summary-mail-other-window
"u" gnus-uu-post-news
"\M-c" gnus-summary-mail-crosspost-complaint
+ "Br" gnus-summary-reply-broken-reply-to
+ "BR" gnus-summary-reply-broken-reply-to-with-original
"om" gnus-summary-mail-forward
"op" gnus-summary-post-forward
"Om" gnus-uu-digest-mail-forward
(setq mml-buffer-list nil)
(add-hook 'message-header-setup-hook 'gnus-inews-insert-gcc)
(add-hook 'message-header-setup-hook 'gnus-inews-insert-archive-gcc)
- (add-hook 'message-mode-hook 'gnus-configure-posting-styles)
+ ;; #### FIXME: for a reason that I did not manage to identify yet,
+ ;; the variable `gnus-newsgroup-name' does not honor a dynamically
+ ;; scoped or setq'ed value from a caller like `C-u gnus-summary-mail'.
+ ;; After evaluation of @forms below, it gets the value we actually want
+ ;; to override, and the posting styles are used. For that reason, I've
+ ;; added an optional argument to `gnus-configure-posting-styles' to
+ ;; make sure that the correct value for the group name is used. -- drv
+ (add-hook 'message-mode-hook
+ (lambda ()
+ (gnus-configure-posting-styles ,group)))
(unwind-protect
(progn
,@forms)
(let ((mbl1 mml-buffer-list))
(setq mml-buffer-list mbl) ;; Global value
(set (make-local-variable 'mml-buffer-list) mbl1);; Local value
+ ;; LOCAL argument of add-hook differs between GNU Emacs
+ ;; and XEmacs. make-local-hook makes sure they are local.
+ (make-local-hook 'kill-buffer-hook)
+ (make-local-hook 'change-major-mode-hook)
+ (add-hook 'change-major-mode-hook 'mml-destroy-buffers nil t)
(add-hook 'kill-buffer-hook 'mml-destroy-buffers t t))
(mml-destroy-buffers)
(setq mml-buffer-list mbl)))
(gnus-add-buffer)
(gnus-configure-windows ,config t)
+ (run-hooks 'post-command-hook)
(set-buffer-modified-p nil))))
(defun gnus-inews-insert-draft-meta-information (group article)
;; COMPOSEFUNC should return t if succeed. Undocumented ???
t)
+(defvar save-selected-window-window)
+
;;;###autoload
(defun gnus-button-mailto (address)
"Mail to ADDRESS."
(set-buffer (gnus-copy-article-buffer))
(gnus-setup-message 'message
- (message-reply address)))
+ (message-reply address))
+ (and (boundp 'save-selected-window-window)
+ (not (window-live-p save-selected-window-window))
+ (setq save-selected-window-window (selected-window))))
;;;###autoload
(defun gnus-button-reply (&optional to-address wide)
"Like `message-reply'."
(interactive)
(gnus-setup-message 'message
- (message-reply to-address wide)))
+ (message-reply to-address wide))
+ (and (boundp 'save-selected-window-window)
+ (not (window-live-p save-selected-window-window))
+ (setq save-selected-window-window (selected-window))))
;;;###autoload
(define-mail-user-agent 'gnus-user-agent
(gnus-read-active-file-p))
(gnus-group-group-name))
""))
+ ;; #### see comment in gnus-setup-message -- drv
(gnus-setup-message 'message (message-mail)))
(save-excursion
(set-buffer buffer)
(setq gnus-newsgroup-name group)))))
+(defun gnus-group-news (&optional arg)
+ "Start composing a news.
+If ARG, post to group under point.
+If ARG is 1, prompt for group name to post to.
+
+This function prepares a news even when using mail groups. This is useful
+for posting messages to mail groups without actually sending them over the
+network. The corresponding backend must have a 'request-post method."
+ (interactive "P")
+ ;; We can't `let' gnus-newsgroup-name here, since that leads
+ ;; to local variables leaking.
+ (let ((group gnus-newsgroup-name)
+ (buffer (current-buffer)))
+ (unwind-protect
+ (progn
+ (setq gnus-newsgroup-name
+ (if arg
+ (if (= 1 (prefix-numeric-value arg))
+ (completing-read "Use group: "
+ gnus-active-hashtb nil
+ (gnus-read-active-file-p))
+ (gnus-group-group-name))
+ ""))
+ ;; #### see comment in gnus-setup-message -- drv
+ (gnus-setup-message 'message
+ (message-news (gnus-group-real-name gnus-newsgroup-name))))
+ (save-excursion
+ (set-buffer buffer)
+ (setq gnus-newsgroup-name group)))))
+
(defun gnus-group-post-news (&optional arg)
- "Start composing a news message.
-If ARG, post to the group under point.
-If ARG is 1, prompt for a group name."
+ "Start composing a message (a news by default).
+If ARG, post to group under point. If ARG is 1, prompt for group name.
+Depending on the selected group, the message might be either a mail or
+a news."
(interactive "P")
;; Bind this variable here to make message mode hooks work ok.
(let ((gnus-newsgroup-name
"")))
(gnus-post-news 'post gnus-newsgroup-name)))
-(defun gnus-summary-post-news ()
- "Start composing a news message."
- (interactive)
- (gnus-post-news 'post gnus-newsgroup-name))
+(defun gnus-summary-mail-other-window (&optional arg)
+ "Start composing a mail in another window.
+Use the posting of the current group by default.
+If ARG, don't do that. If ARG is 1, prompt for group name to find the
+posting style."
+ (interactive "P")
+ ;; We can't `let' gnus-newsgroup-name here, since that leads
+ ;; to local variables leaking.
+ (let ((group gnus-newsgroup-name)
+ (buffer (current-buffer)))
+ (unwind-protect
+ (progn
+ (setq gnus-newsgroup-name
+ (if arg
+ (if (= 1 (prefix-numeric-value arg))
+ (completing-read "Use group: "
+ gnus-active-hashtb nil
+ (gnus-read-active-file-p))
+ "")
+ gnus-newsgroup-name))
+ ;; #### see comment in gnus-setup-message -- drv
+ (gnus-setup-message 'message (message-mail)))
+ (save-excursion
+ (set-buffer buffer)
+ (setq gnus-newsgroup-name group)))))
+
+(defun gnus-summary-news-other-window (&optional arg)
+ "Start composing a news in another window.
+Post to the current group by default.
+If ARG, don't do that. If ARG is 1, prompt for group name to post to.
+
+This function prepares a news even when using mail groups. This is useful
+for posting messages to mail groups without actually sending them over the
+network. The corresponding backend must have a 'request-post method."
+ (interactive "P")
+ ;; We can't `let' gnus-newsgroup-name here, since that leads
+ ;; to local variables leaking.
+ (let ((group gnus-newsgroup-name)
+ (buffer (current-buffer)))
+ (unwind-protect
+ (progn
+ (setq gnus-newsgroup-name
+ (if arg
+ (if (= 1 (prefix-numeric-value arg))
+ (completing-read "Use group: "
+ gnus-active-hashtb nil
+ (gnus-read-active-file-p))
+ "")
+ gnus-newsgroup-name))
+ ;; #### see comment in gnus-setup-message -- drv
+ (gnus-setup-message 'message
+ (message-news (gnus-group-real-name gnus-newsgroup-name))))
+ (save-excursion
+ (set-buffer buffer)
+ (setq gnus-newsgroup-name group)))))
+
+(defun gnus-summary-post-news (&optional arg)
+ "Start composing a message. Post to the current group by default.
+If ARG, don't do that. If ARG is 1, prompt for a group name to post to.
+Depending on the selected group, the message might be either a mail or
+a news."
+ (interactive "P")
+ ;; Bind this variable here to make message mode hooks work ok.
+ (let ((gnus-newsgroup-name
+ (if arg
+ (if (= 1 (prefix-numeric-value arg))
+ (completing-read "Newsgroup: " gnus-active-hashtb nil
+ (gnus-read-active-file-p))
+ "")
+ gnus-newsgroup-name)))
+ (gnus-post-news 'post gnus-newsgroup-name)))
+
(defun gnus-summary-followup (yank &optional force-news)
"Compose a followup to an article.
(while (looking-at message-unix-mail-delimiter)
(forward-line 1))
(setq beg (point))
- (setq end (or (search-forward "\n\n" nil t) (point)))
+ (setq end (or (message-goto-body) beg))
;; Delete the headers from the displayed articles.
(set-buffer gnus-article-copy)
(delete-region (goto-char (point-min))
- (or (search-forward "\n\n" nil t) (point-max)))
+ (or (message-goto-body) (point-max)))
;; Insert the original article headers.
(insert-buffer-substring gnus-original-article-buffer beg end)
- (article-decode-encoded-words))))
+ ;; Decode charsets.
+ (let ((gnus-article-decode-hook
+ (delq 'article-decode-charset
+ (copy-sequence gnus-article-decode-hook))))
+ (run-hooks 'gnus-article-decode-hook)))))
gnus-article-copy)))
(defun gnus-post-news (post &optional group header article-buffer yank subject
force-news
(and (gnus-news-group-p
(or pgroup gnus-newsgroup-name)
- (if header (mail-header-number header)
- gnus-current-article))
+ (or header gnus-current-article))
(not mailing-list)
(not to-list)
(not to-address)))
(when yank
(gnus-inews-yank-articles yank))))))
-(defun gnus-msg-treat-broken-reply-to ()
+(defun gnus-msg-treat-broken-reply-to (&optional force)
"Remove the Reply-to header iff broken-reply-to."
- (when (gnus-group-find-parameter
- gnus-newsgroup-name 'broken-reply-to)
+ (when (or force
+ (gnus-group-find-parameter
+ gnus-newsgroup-name 'broken-reply-to))
(save-restriction
(message-narrow-to-head)
(message-remove-header "reply-to"))))
(defun gnus-post-method (arg group &optional silent)
"Return the posting method based on GROUP and ARG.
If SILENT, don't prompt the user."
- (let ((group-method (gnus-find-method-for-group group)))
+ (let ((gnus-post-method (or (gnus-parameter-post-method group)
+ gnus-post-method))
+ (group-method (gnus-find-method-for-group group)))
(cond
;; If the group-method is nil (which shouldn't happen) we use
;; the default method.
((null group-method)
- (or (and (null (eq gnus-post-method 'active)) gnus-post-method)
- gnus-select-method message-post-method))
+ (or (and (listp gnus-post-method) ;If not current/native/nil
+ (not (listp (car gnus-post-method))) ; and not a list of methods
+ gnus-post-method) ;then use it.
+ gnus-select-method
+ message-post-method))
;; We want the inverse of the default
((and arg (not (eq arg 0)))
- (if (eq gnus-post-method 'active)
+ (if (eq gnus-post-method 'current)
gnus-select-method
group-method))
;; We query the user for a post method.
((or arg
- (and gnus-post-method
- (not (eq gnus-post-method 'current))
+ (and (listp gnus-post-method)
(listp (car gnus-post-method))))
(let* ((methods
;; Collect all methods we know about.
(append
- (when (and gnus-post-method
- (not (eq gnus-post-method 'current)))
+ (when (listp gnus-post-method)
(if (listp (car gnus-post-method))
gnus-post-method
(list gnus-post-method)))
;; Override normal method.
((and (eq gnus-post-method 'current)
(not (eq (car group-method) 'nndraft))
- (gnus-get-function group-method 'request-post t)
- (not arg))
+ (gnus-get-function group-method 'request-post t))
+ (assert (not arg))
group-method)
- ((and gnus-post-method
- (not (eq gnus-post-method 'current)))
+ ;; Use gnus-post-method.
+ ((listp gnus-post-method) ;A method...
+ (assert (not (listp (car gnus-post-method)))) ;... not a list of methods.
gnus-post-method)
- ;; Use the normal select method.
+ ;; Use the normal select method (nil or native).
(t gnus-select-method))))
\f
" "
(cond
((string-match "^\\(\\([.0-9]+\\)*\\)\\.[0-9]+$" emacs-version)
- (concat "Emacs/" (match-string 1 emacs-version)))
+ (concat "Emacs/" (match-string 1 emacs-version)
+ " (" system-configuration ")"))
((string-match "\\([A-Z]*[Mm][Aa][Cc][Ss]\\)[^(]*\\(\\((beta.*)\\|'\\)\\)?"
emacs-version)
(concat (match-string 1 emacs-version)
(match-string 3 emacs-version)
"")
(if (boundp 'xemacs-codename)
- (concat " (" xemacs-codename ")")
+ (concat " (" xemacs-codename ", " system-configuration ")")
"")))
(t emacs-version))))
(message-narrow-to-head)
(setq headers (concat headers (buffer-string)))))))
(set-buffer (gnus-copy-article-buffer))
- (gnus-msg-treat-broken-reply-to)
+ (gnus-msg-treat-broken-reply-to gnus-msg-force-broken-reply-to)
(save-restriction
(message-narrow-to-head)
(when very-wide
(interactive "P")
(gnus-summary-reply (gnus-summary-work-articles n) wide))
+(defun gnus-summary-reply-broken-reply-to (&optional yank wide very-wide)
+ "Like `gnus-summary-reply' except removing reply-to field.
+If prefix argument YANK is non-nil, the original article is yanked
+automatically.
+If WIDE, make a wide reply.
+If VERY-WIDE, make a very wide reply."
+ (interactive
+ (list (and current-prefix-arg
+ (gnus-summary-work-articles 1))))
+ (let ((gnus-msg-force-broken-reply-to t))
+ (gnus-summary-reply yank wide very-wide)))
+
+(defun gnus-summary-reply-broken-reply-to-with-original (n &optional wide)
+ "Like `gnus-summary-reply-with-original' except removing reply-to field.
+The original article will be yanked."
+ (interactive "P")
+ (gnus-summary-reply-broken-reply-to (gnus-summary-work-articles n) wide))
+
(defun gnus-summary-wide-reply (&optional yank)
"Start composing a wide reply mail to the current message.
If prefix argument YANK is non-nil, the original article is yanked
(gnus-summary-work-articles n) t (gnus-summary-work-articles n)))
(defun gnus-summary-mail-forward (&optional arg post)
- "Forward the current message to another user.
-If ARG is nil, see `message-forward-as-mime' and `message-forward-show-mml';
+ "Forward the current message(s) to another user.
+If process marks exist, forward all marked messages;
+if ARG is nil, see `message-forward-as-mime' and `message-forward-show-mml';
if ARG is 1, decode the message and forward directly inline;
if ARG is 2, forward message as an rfc822 MIME section;
if ARG is 3, decode message and forward as an rfc822 MIME section;
if ARG is 4, forward message directly inline;
otherwise, use flipped `message-forward-as-mime'.
-If POST, post instead of mail."
+If POST, post instead of mail.
+For the `inline' alternatives, also see the variable
+`message-forward-ignored-headers'."
(interactive "P")
- (let ((message-forward-as-mime message-forward-as-mime)
- (message-forward-show-mml message-forward-show-mml))
- (cond
- ((null arg))
- ((eq arg 1)
- (setq message-forward-as-mime nil
- message-forward-show-mml t))
- ((eq arg 2)
- (setq message-forward-as-mime t
- message-forward-show-mml nil))
- ((eq arg 3)
- (setq message-forward-as-mime t
- message-forward-show-mml t))
- ((eq arg 4)
- (setq message-forward-as-mime nil
- message-forward-show-mml nil))
- (t
- (setq message-forward-as-mime (not message-forward-as-mime))))
- (let ((gnus-article-reply (gnus-summary-article-number)))
- (gnus-setup-message 'forward
- (gnus-summary-select-article)
- (let ((mail-parse-charset gnus-newsgroup-charset)
- (mail-parse-ignored-charsets gnus-newsgroup-ignored-charsets))
- (set-buffer gnus-original-article-buffer)
- (message-forward post))))))
+ (if (null (cdr (gnus-summary-work-articles nil)))
+ (let ((message-forward-as-mime message-forward-as-mime)
+ (message-forward-show-mml message-forward-show-mml))
+ (cond
+ ((null arg))
+ ((eq arg 1)
+ (setq message-forward-as-mime nil
+ message-forward-show-mml t))
+ ((eq arg 2)
+ (setq message-forward-as-mime t
+ message-forward-show-mml nil))
+ ((eq arg 3)
+ (setq message-forward-as-mime t
+ message-forward-show-mml t))
+ ((eq arg 4)
+ (setq message-forward-as-mime nil
+ message-forward-show-mml nil))
+ (t
+ (setq message-forward-as-mime (not message-forward-as-mime))))
+ (let ((gnus-article-reply (gnus-summary-article-number)))
+ (gnus-setup-message 'forward
+ (gnus-summary-select-article)
+ (let ((mail-parse-charset gnus-newsgroup-charset)
+ (mail-parse-ignored-charsets gnus-newsgroup-ignored-charsets))
+ (set-buffer gnus-original-article-buffer)
+ (message-forward post)))))
+ (gnus-uu-digest-mail-forward arg post)))
(defun gnus-summary-resend-message (address n)
"Resend the current article to ADDRESS."
(when (gnus-y-or-n-p "Send this complaint? ")
(message-send-and-exit)))))))
-(defun gnus-summary-mail-other-window ()
- "Compose mail in other window."
- (interactive)
- (gnus-setup-message 'message
- (message-mail)))
-
(defun gnus-mail-parse-comma-list ()
(let (accumulated
beg)
(let (text)
(save-excursion
(set-buffer (gnus-get-buffer-create " *gnus environment info*"))
+ (erase-buffer)
(gnus-debug)
(setq text (buffer-string)))
(insert "<#part type=application/x-emacs-lisp disposition=inline description=\"User settings\">\n" text "\n<#/part>"))
;;; Gcc handling.
(defun gnus-inews-group-method (group)
- (cond ((and (null (gnus-get-info group))
- (eq (car gnus-message-archive-method)
- (car
- (gnus-server-to-method
- (gnus-group-method group)))))
- ;; If the group doesn't exist, we assume
- ;; it's an archive group...
- gnus-message-archive-method)
- ;; Use the method.
- ((gnus-info-method (gnus-get-info group))
- (gnus-info-method (gnus-get-info group)))
- ;; Find the method.
- (t (gnus-group-method group))))
+ (cond
+ ;; If the group doesn't exist, we assume
+ ;; it's an archive group...
+ ((and (null (gnus-get-info group))
+ (eq (car (gnus-server-to-method gnus-message-archive-method))
+ (car (gnus-server-to-method (gnus-group-method group)))))
+ gnus-message-archive-method)
+ ;; Use the method.
+ ((gnus-info-method (gnus-get-info group))
+ (gnus-info-method (gnus-get-info group)))
+ ;; Find the method.
+ (t (gnus-server-to-method (gnus-group-method group)))))
;; Do Gcc handling, which copied the message over to some group.
(defun gnus-inews-do-gcc (&optional gcc)
(interactive)
- (when (gnus-alive-p)
- (save-excursion
- (save-restriction
- (message-narrow-to-headers)
- (let ((gcc (or gcc (mail-fetch-field "gcc" nil t)))
- (cur (current-buffer))
- groups group method group-art)
- (when gcc
- (message-remove-header "gcc")
- (widen)
- (setq groups (message-unquote-tokens
- (message-tokenize-header gcc " ,")))
- ;; Copy the article over to some group(s).
- (while (setq group (pop groups))
- (gnus-check-server
- (setq method (gnus-inews-group-method group)))
- (unless (gnus-request-group group nil method)
- (gnus-request-create-group group method))
- (save-excursion
- (nnheader-set-temp-buffer " *acc*")
- (insert-buffer-substring cur)
- (message-encode-message-body)
- (save-restriction
- (message-narrow-to-headers)
- (let ((mail-parse-charset message-default-charset)
- (rfc2047-header-encoding-alist
- (cons '("Newsgroups" . default)
- rfc2047-header-encoding-alist)))
- (mail-encode-encoded-word-buffer)))
- (goto-char (point-min))
- (when (re-search-forward
- (concat "^" (regexp-quote mail-header-separator) "$")
- nil t)
- (replace-match "" t t ))
- (unless (setq group-art
- (gnus-request-accept-article group method t t))
- (gnus-message 1 "Couldn't store article in group %s: %s"
- group (gnus-status-message method))
- (sit-for 2))
- (when (and group-art gnus-inews-mark-gcc-as-read)
- (gnus-group-mark-article-read group (cdr group-art)))
- (kill-buffer (current-buffer))))))))))
+ (save-excursion
+ (save-restriction
+ (message-narrow-to-headers)
+ (let ((gcc (or gcc (mail-fetch-field "gcc" nil t)))
+ (cur (current-buffer))
+ groups group method group-art)
+ (when gcc
+ (message-remove-header "gcc")
+ (widen)
+ (setq groups (message-unquote-tokens
+ (message-tokenize-header gcc " ,")))
+ ;; Copy the article over to some group(s).
+ (while (setq group (pop groups))
+ (unless (gnus-check-server
+ (setq method (gnus-inews-group-method group)))
+ (error "Can't open server %s" (if (stringp method) method
+ (car method))))
+ (unless (gnus-request-group group nil method)
+ (gnus-request-create-group group method))
+ (save-excursion
+ (nnheader-set-temp-buffer " *acc*")
+ (insert-buffer-substring cur)
+ (message-encode-message-body)
+ (save-restriction
+ (message-narrow-to-headers)
+ (let* ((mail-parse-charset message-default-charset)
+ (newsgroups-field (save-restriction
+ (message-narrow-to-headers-or-head)
+ (message-fetch-field "Newsgroups")))
+ (followup-field (save-restriction
+ (message-narrow-to-headers-or-head)
+ (message-fetch-field "Followup-To")))
+ ;; BUG: We really need to get the charset for
+ ;; each name in the Newsgroups and Followup-To
+ ;; lines to allow crossposting between group
+ ;; namess with incompatible character sets.
+ ;; -- Per Abrahamsen <abraham@dina.kvl.dk> 2001-10-08.
+ (group-field-charset
+ (gnus-group-name-charset
+ method (or newsgroups-field "")))
+ (followup-field-charset
+ (gnus-group-name-charset
+ method (or followup-field "")))
+ (rfc2047-header-encoding-alist
+ (append
+ (when group-field-charset
+ (list (cons "Newsgroups" group-field-charset)))
+ (when followup-field-charset
+ (list (cons "Followup-To" followup-field-charset)))
+ rfc2047-header-encoding-alist)))
+ (mail-encode-encoded-word-buffer)))
+ (goto-char (point-min))
+ (when (re-search-forward
+ (concat "^" (regexp-quote mail-header-separator) "$")
+ nil t)
+ (replace-match "" t t ))
+ (unless (setq group-art
+ (gnus-request-accept-article group method t t))
+ (gnus-message 1 "Couldn't store article in group %s: %s"
+ group (gnus-status-message method))
+ (sit-for 2))
+ (when (and group-art gnus-inews-mark-gcc-as-read)
+ (gnus-group-mark-article-read group (cdr group-art)))
+ (kill-buffer (current-buffer)))))))))
(defun gnus-inews-insert-gcc ()
"Insert Gcc headers based on `gnus-outgoing-message-group'."
;;; Posting styles.
-(defun gnus-configure-posting-styles ()
+(defun gnus-configure-posting-styles (&optional group-name)
"Configure posting styles according to `gnus-posting-styles'."
(unless gnus-inhibit-posting-styles
- (let ((group (or gnus-newsgroup-name ""))
+ (let ((group (or group-name gnus-newsgroup-name ""))
(styles gnus-posting-styles)
style match variable attribute value v results
filep name address element)
(setq name (assq 'name results)
address (assq 'address results))
(setq results (delq name (delq address results)))
- (make-local-variable 'message-setup-hook)
+ ;; make-local-hook is not obsolete in Emacs 20 or XEmacs.
+ (make-local-hook 'message-setup-hook)
(dolist (result results)
(add-hook 'message-setup-hook
(cond
(let ((value ,(cdr result)))
(when value
(message-goto-eoh)
- (insert ,header ": " value "\n"))))))))))
+ (insert ,header ": " value "\n"))))))))
+ nil 'local))
(when (or name address)
(add-hook 'message-setup-hook
`(lambda ()
- (set (make-local-variable 'user-mail-address)
- ,(or (cdr address) user-mail-address))
+ (set (make-local-variable 'user-mail-address)
+ ,(or (cdr address) user-mail-address))
(let ((user-full-name ,(or (cdr name) (user-full-name)))
(user-mail-address
,(or (cdr address) user-mail-address)))
(save-excursion
(message-remove-header "From")
(message-goto-eoh)
- (insert "From: " (message-make-from) "\n")))))))))
+ (insert "From: " (message-make-from) "\n"))))
+ nil 'local)))))
;;; Allow redefinition of functions.
;;; gnus-picon.el --- displaying pretty icons in Gnus
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
;; Author: Wes Hardaker <hardaker@ece.ucdavis.edu>
;;; Commentary:
+;; There are three picon types relevant to Gnus:
+;;
+;; Persons: person@subdomain.dom
+;; users/dom/subdomain/person/face.gif
+;; usenix/dom/subdomain/person/face.gif
+;; misc/MISC/person/face.gif
+;; Domains: subdomain.dom
+;; domain/dom/subdomain/unknown/face.gif
+;; Groups: comp.lang.lisp
+;; news/comp/lang/lisp/unknown/face.gif
+
;;; Code:
(require 'gnus)
-;; (require 'xpm)
-(require 'annotations)
(require 'custom)
(require 'gnus-art)
-(require 'gnus-win)
;;; User variables:
-(defgroup picons nil
- "Show pictures of people, domains, and newsgroups (XEmacs).
-For this to work, you must switch on the `gnus-treat-display-picons'
-variable."
+(defgroup picon nil
+ "Show pictures of people, domains, and newsgroups."
:group 'gnus-visual)
-(defcustom gnus-picons-display-where 'picons
- "Where to display the group and article icons.
-Valid values are `article' and `picons'."
- :type '(choice symbol string)
- :group 'picons)
-
-(defcustom gnus-picons-has-modeline-p t
- "*Whether the picons window should have a modeline.
-This is only useful if `gnus-picons-display-where' is `picons'."
- :type 'boolean
- :group 'picons)
-
-(defcustom gnus-picons-database "/usr/local/faces"
+(defcustom gnus-picon-databases '("/usr/lib/picon" "/usr/local/faces")
"*Defines the location of the faces database.
For information on obtaining this database of pretty pictures, please
see http://www.cs.indiana.edu/picons/ftp/index.html"
:type 'directory
- :group 'picons)
+ :group 'picon)
-(defcustom gnus-picons-news-directories '("news")
+(defcustom gnus-picon-news-directories '("news")
"*List of directories to search for newsgroups faces."
:type '(repeat string)
- :group 'picons)
-(define-obsolete-variable-alias 'gnus-picons-news-directory
- 'gnus-picons-news-directories)
+ :group 'picon)
-(defcustom gnus-picons-user-directories '("local" "users" "usenix" "misc")
+(defcustom gnus-picon-user-directories '("users" "usenix" "local" "misc")
"*List of directories to search for user faces."
:type '(repeat string)
- :group 'picons)
+ :group 'picon)
-(defcustom gnus-picons-domain-directories '("domains")
+(defcustom gnus-picon-domain-directories '("domains")
"*List of directories to search for domain faces.
Some people may want to add \"unknown\" to this list."
:type '(repeat string)
- :group 'picons)
-
-(defcustom gnus-picons-refresh-before-display nil
- "*If non-nil, display the article buffer before computing the picons."
- :type 'boolean
- :group 'picons)
-
-(defcustom gnus-picons-group-excluded-groups nil
- "*If this regexp matches the group name, group picons will be disabled."
- :type 'regexp
- :group 'picons)
-
-(defcustom gnus-picons-display-as-address t
- "*If t display textual email addresses along with pictures."
- :type 'boolean
- :group 'picons)
-
-(defcustom gnus-picons-file-suffixes
- (when (featurep 'x)
- (let ((types (list "xbm")))
- (when (featurep 'gif)
- (push "gif" types))
- (when (featurep 'xpm)
- (push "xpm" types))
- types))
+ :group 'picon)
+
+(defcustom gnus-picon-file-types
+ (let ((types (list "xbm")))
+ (when (gnus-image-type-available-p 'gif)
+ (push "gif" types))
+ (when (gnus-image-type-available-p 'xpm)
+ (push "xpm" types))
+ types)
"*List of suffixes on picon file names to try."
:type '(repeat string)
- :group 'picons)
-
-(defcustom gnus-picons-display-article-move-p nil
- "*Whether to move point to first empty line when displaying picons.
-This has only an effect if `gnus-picons-display-where' has value `article'."
- :type 'boolean
- :group 'picons)
-
-(defcustom gnus-picons-clear-cache-on-shutdown t
- "*Whether to clear the picons cache when exiting gnus.
-Gnus caches every picons it finds while it is running. This saves
-some time in the search process but eats some memory. If this
-variable is set to nil, Gnus will never clear the cache itself; you
-will have to manually call `gnus-picons-clear-cache' to clear it.
-Otherwise the cache will be cleared every time you exit Gnus."
- :type 'boolean
- :group 'picons)
-
-(defcustom gnus-picons-piconsearch-url nil
- "*The url to query for picons. Setting this to nil will disable it.
-The only publicly available address currently known is
-http://www.cs.indiana.edu:800/piconsearch. If you know of any other,
-please tell me so that we can list it."
- :type '(choice (const :tag "Disable" :value nil)
- (const :tag "www.cs.indiana.edu"
- :value "http://www.cs.indiana.edu:800/piconsearch")
- (string))
- :group 'picons)
-
-(defface gnus-picons-xbm-face '((t (:foreground "black" :background "white")))
- "Face to show xbm picons in."
- :group 'picons)
-
-(defface gnus-picons-face '((t (:foreground "black" :background "white")))
- "Face to show picons in."
- :group 'picons)
-
-(defcustom gnus-picons-setup-hook nil
- "Hook run in Picons buffers."
- :group 'picons
- :type 'hook)
+ :group 'picon)
-;;; Internal variables:
+(defface gnus-picon-xbm-face '((t (:foreground "black" :background "white")))
+ "Face to show xbm picon in."
+ :group 'picon)
-(defvar gnus-picons-setup-p nil)
-(defvar gnus-picons-processes-alist nil
- "Picons processes currently running and their environment.")
-(defvar gnus-picons-glyph-alist nil
- "Picons glyphs cache.
-List of pairs (KEY . GLYPH) where KEY is either a filename or an URL.")
-(defvar gnus-picons-url-alist nil
- "Picons file names cache.
-List of pairs (KEY . NAME) where KEY is (USER HOST DBS) and NAME is an URL.")
+(defface gnus-picon-face '((t (:foreground "black" :background "white")))
+ "Face to show picon in."
+ :group 'picon)
-(defvar gnus-picons-jobs-alist nil
- "List of jobs that still need be done.
-This is a list of (SYM-ANN TAG ARGS...) where SYM-ANN three annotations list,
-TAG is one of `picon' or `search' indicating that the job should query a
-picon or do a search for picons file names, and ARGS is some additionnal
-arguments necessary for the job.")
+;;; Internal variables:
-(defvar gnus-picons-job-already-running nil
- "Lock to ensure only one stream of http requests is running.")
+(defvar gnus-picon-setup-p nil)
+(defvar gnus-picon-glyph-alist nil
+ "Picon glyphs cache.
+List of pairs (KEY . GLYPH) where KEY is either a filename or an URL.")
;;; Functions:
-(defun gnus-picons-remove-all ()
- "Removes all picons from the Gnus display(s)."
+(defsubst gnus-picon-split-address (address)
+ (setq address (split-string address "@"))
+ (if (stringp (cadr address))
+ (cons (car address) (split-string (cadr address) "\\."))
+ (if (stringp (car address))
+ (split-string (car address) "\\."))))
+
+(defun gnus-picon-find-face (address directories &optional exact)
+ (let* ((databases gnus-picon-databases)
+ (address (gnus-picon-split-address address))
+ (user (pop address))
+ database directory found instance base)
+ (while (and (not found)
+ (setq database (pop databases)))
+ (while (and (not found)
+ (setq directory (pop directories)))
+ (setq base (expand-file-name directory database))
+ ;; Kludge to search misc/MISC for users.
+ (when (string= directory "misc")
+ (setq address '("MISC")))
+ (while (and (not found)
+ address)
+ (setq found (gnus-picon-find-image
+ (concat base "/" (mapconcat 'identity
+ (reverse address)
+ "/")
+ "/" user "/")))
+ (if exact
+ (setq address nil)
+ (pop address)))))
+ found))
+
+(defun gnus-picon-find-image (directory)
+ (let ((types gnus-picon-file-types)
+ found type file)
+ (while (and (not found)
+ (setq type (pop types)))
+ (setq found (file-exists-p (setq file (concat directory "face." type)))))
+ (if found
+ file
+ nil)))
+
+(defun gnus-picon-insert-glyph (glyph category)
+ "Insert GLYPH into the buffer.
+GLYPH can be either a glyph or a string."
+ (if (stringp glyph)
+ (insert glyph)
+ (gnus-add-wash-type category)
+ (gnus-add-image category (car glyph))
+ (gnus-put-image (car glyph) (cdr glyph))))
+
+(defun gnus-picon-create-glyph (file)
+ (or (cdr (assoc file gnus-picon-glyph-alist))
+ (cdar (push (cons file (gnus-create-image file))
+ gnus-picon-glyph-alist))))
+
+;;; Functions that does picon transformations:
+
+(defun gnus-picon-transform-address (header category)
+ (gnus-with-article-headers
+ (let ((addresses
+ (mail-header-parse-addresses (mail-fetch-field header)))
+ first spec file)
+ (dolist (address addresses)
+ (setq address (car address)
+ first t)
+ (when (and (stringp address)
+ (setq spec (gnus-picon-split-address address)))
+ (when (setq file (gnus-picon-find-face
+ address gnus-picon-user-directories))
+ (setcar spec (cons (gnus-picon-create-glyph file)
+ (car spec))))
+ (dotimes (i (1- (length spec)))
+ (when (setq file (gnus-picon-find-face
+ (concat "unknown@"
+ (mapconcat
+ 'identity (nthcdr (1+ i) spec) "."))
+ gnus-picon-domain-directories t))
+ (setcar (nthcdr (1+ i) spec)
+ (cons (gnus-picon-create-glyph file)
+ (nth (1+ i) spec)))))
+
+ (gnus-article-goto-header header)
+ (mail-header-narrow-to-field)
+ (when (search-forward address nil t)
+ (delete-region (match-beginning 0) (match-end 0))
+ (while spec
+ (gnus-picon-insert-glyph (pop spec) category)
+ (when spec
+ (if (not first)
+ (insert ".")
+ (insert "@")
+ (setq first nil))))))))))
+
+(defun gnus-picon-transform-newsgroups (header)
(interactive)
- (map-extents (function (lambda (ext unused) (delete-annotation ext) nil))
- nil nil nil nil nil 'gnus-picon)
- (setq gnus-picons-jobs-alist '())
- ;; notify running job that it may have been preempted
- (if (and (listp gnus-picons-job-already-running)
- gnus-picons-job-already-running)
- (setq gnus-picons-job-already-running t)))
-
-(defun gnus-get-buffer-name (variable)
- "Returns the buffer name associated with the contents of a variable."
- (let ((buf (gnus-get-buffer-create
- (gnus-window-to-buffer-helper
- (cdr (assq variable gnus-window-to-buffer))))))
- (and buf
- (buffer-name buf))))
-
-(defun gnus-picons-buffer-name ()
- (cond ((or (stringp gnus-picons-display-where)
- (bufferp gnus-picons-display-where))
- gnus-picons-display-where)
- ((eq gnus-picons-display-where 'picons)
- (if gnus-single-article-buffer
- "*Picons*"
- (concat "*Picons " gnus-newsgroup-name "*")))
- (t
- (gnus-get-buffer-name gnus-picons-display-where))))
-
-(defun gnus-picons-kill-buffer ()
- (let ((buf (get-buffer (gnus-picons-buffer-name))))
- (when (and (buffer-live-p buf)
- (string-match "Picons" (buffer-name buf)))
- (kill-buffer buf))))
-
-(defun gnus-picons-setup-buffer ()
- (let ((name (gnus-picons-buffer-name)))
- (save-excursion
- (if (and (get-buffer name)
- (with-current-buffer name
- gnus-picons-setup-p))
- (set-buffer name)
- (set-buffer (gnus-get-buffer-create name))
- (buffer-disable-undo)
- (setq buffer-read-only t)
- (run-hooks 'gnus-picons-setup-hook)
- (set (make-local-variable 'gnus-picons-setup-p) t)
- (add-hook 'gnus-summary-prepare-exit-hook 'gnus-picons-kill-buffer))
- (current-buffer))))
-
-(defun gnus-picons-set-buffer ()
- (set-buffer (gnus-picons-setup-buffer))
- (goto-char (point-min))
- (if (and (eq gnus-picons-display-where 'article)
- gnus-picons-display-article-move-p)
- (if (search-forward "\n\n" nil t)
- (forward-line -1)
- (goto-char (point-max)))
- (setq buffer-read-only t)
- (unless gnus-picons-has-modeline-p
- (set-specifier has-modeline-p
- (list (list (current-buffer)
- (cons nil gnus-picons-has-modeline-p)))))))
-
-(defun gnus-picons-prepare-for-annotations ()
- "Prepare picons buffer for putting annotations."
- ;; let drawing catch up
- (when gnus-picons-refresh-before-display
- (sit-for 0))
- (gnus-picons-set-buffer)
- (gnus-picons-remove-all))
-
-(defun gnus-picons-make-annotation (&rest args)
- (let ((annot (apply 'make-annotation args)))
- (set-extent-property annot 'gnus-picon t)
- (set-extent-property annot 'duplicable t)
- annot))
-
-(defun gnus-article-display-picons ()
- "Display faces for an author and her domain in gnus-picons-display-where."
+ (gnus-with-article-headers
+ (let ((groups
+ (sort
+ (message-tokenize-header (mail-fetch-field header))
+ (lambda (g1 g2) (> (length g1) (length g2)))))
+ spec file)
+ (dolist (group groups)
+ (setq spec (nreverse (split-string group "[.]")))
+ (dotimes (i (length spec))
+ (when (setq file (gnus-picon-find-face
+ (concat "unknown@"
+ (mapconcat
+ 'identity (nthcdr i spec) "."))
+ gnus-picon-news-directories t))
+ (setcar (nthcdr i spec)
+ (cons (gnus-picon-create-glyph file)
+ (nth i spec)))))
+
+ (gnus-article-goto-header header)
+ (mail-header-narrow-to-field)
+ (when (search-forward group nil t)
+ (delete-region (match-beginning 0) (match-end 0))
+ (setq spec (nreverse spec))
+ (while spec
+ (gnus-picon-insert-glyph (pop spec) 'newsgroups-picon)
+ (when spec
+ (insert "."))))))))
+
+;;; Commands:
+
+;;;###autoload
+(defun gnus-treat-from-picon ()
+ "Display picons in the From header.
+If picons are already displayed, remove them."
(interactive)
- (let (from at-idx)
- (when (and (featurep 'xpm)
- (or (not (fboundp 'device-type)) (equal (device-type) 'x))
- (setq from (mail-fetch-field "from"))
- (setq from (downcase (or (cadr (mail-extract-address-components
- from))
- "")))
- (or (setq at-idx (string-match "@" from))
- (setq at-idx (length from))))
- (save-excursion
- (let ((username (downcase (substring from 0 at-idx)))
- (addrs (if (eq at-idx (length from))
- (if gnus-local-domain
- (message-tokenize-header gnus-local-domain "."))
- (message-tokenize-header (substring from (1+ at-idx))
- "."))))
- (gnus-picons-prepare-for-annotations)
- (gnus-group-display-picons)
- (unless gnus-picons-display-article-move-p
- (let ((buffer-read-only nil)
- (case-fold-search t))
- (when (re-search-forward "^From *: *" nil t)
- (when (search-forward from (gnus-point-at-eol) t)
- (gnus-put-text-property
- (match-beginning 0) (match-end 0)
- 'invisible t)))))
- (if (null gnus-picons-piconsearch-url)
- (progn
- (gnus-picons-display-pairs (gnus-picons-lookup-pairs
- addrs
- gnus-picons-domain-directories)
- gnus-picons-display-as-address
- "." t)
- (if (and gnus-picons-display-as-address addrs)
- (gnus-picons-make-annotation
- [string :data "@"] nil 'text nil nil nil t))
- (gnus-picons-display-picon-or-name
- (gnus-picons-lookup-user username addrs)
- username t))
- (push (list 'gnus-article-annotations 'search username addrs
- gnus-picons-domain-directories t (point-marker))
- gnus-picons-jobs-alist)
- (gnus-picons-next-job)))))))
-
-(defun gnus-group-display-picons ()
- "Display icons for the group in the `gnus-picons-display-where' buffer."
+ (gnus-with-article-buffer
+ (if (memq 'from-picon gnus-article-wash-types)
+ (gnus-delete-images 'from-picon)
+ (gnus-picon-transform-address "from" 'from-picon))))
+
+;;;###autoload
+(defun gnus-treat-mail-picon ()
+ "Display picons in the Cc and To headers.
+If picons are already displayed, remove them."
(interactive)
- (when (and (featurep 'xpm)
- (or (not (fboundp 'device-type)) (equal (device-type) 'x))
- (or (null gnus-picons-group-excluded-groups)
- (not (string-match gnus-picons-group-excluded-groups
- gnus-newsgroup-name))))
- (let* ((newsgroups (mail-fetch-field "newsgroups"))
- (groups
- (if (or gnus-picons-display-article-move-p
- (not newsgroups))
- (list (gnus-group-real-name gnus-newsgroup-name))
- (split-string newsgroups ",")))
- group)
- (save-excursion
- (gnus-picons-prepare-for-annotations)
- (while (setq group (pop groups))
- (unless gnus-picons-display-article-move-p
- (let ((buffer-read-only nil)
- (case-fold-search t))
- (goto-char (point-min))
- (if (and (re-search-forward "^Newsgroups *: *" nil t)
- (search-forward group (gnus-point-at-eol) t))
- (gnus-put-text-property
- (match-beginning 0) (match-end 0)
- 'invisible t)
- (let ((article-goto-body-goes-to-point-min-p nil))
- (article-goto-body))
- (unless (bobp)
- (backward-char 1)))))
- (if (null gnus-picons-piconsearch-url)
- (gnus-picons-display-pairs
- (gnus-picons-lookup-pairs
- (reverse (split-string group "\\."))
- gnus-picons-news-directories)
- t ".")
- (push (list 'gnus-group-annotations 'search nil
- (split-string group "\\.")
- (if (listp gnus-picons-news-directories)
- gnus-picons-news-directories
- (list gnus-picons-news-directories))
- nil (point-marker))
- gnus-picons-jobs-alist)
- (gnus-picons-next-job))
-
- (add-hook 'gnus-summary-exit-hook 'gnus-picons-remove-all))))))
-
-(defun gnus-picons-lookup-internal (addrs dir)
- (setq dir (expand-file-name dir gnus-picons-database))
- (gnus-picons-try-face (dolist (part (reverse addrs) dir)
- (setq dir (expand-file-name part dir)))))
-
-(defun gnus-picons-lookup (addrs dirs)
- "Lookup the picon for ADDRS in databases DIRS.
-Returns the picon filename or NIL if none found."
- (let (result)
- (while (and dirs (null result))
- (setq result (gnus-picons-lookup-internal addrs (pop dirs))))
- result))
-
-(defun gnus-picons-lookup-user-internal (user domains)
- (let ((dirs gnus-picons-user-directories)
- domains-tmp dir picon)
- (while (and dirs (null picon))
- (setq domains-tmp domains
- dir (pop dirs))
- (while (and domains-tmp
- (null (setq picon (gnus-picons-lookup-internal
- (cons user domains-tmp) dir))))
- (pop domains-tmp))
- ;; Also make a try in MISC subdir
- (unless picon
- (setq picon (gnus-picons-lookup-internal (list user "MISC") dir))))
- picon))
-
-(defun gnus-picons-lookup-user (user domains)
- "Lookup the picon for USER at DOMAINS.
-USER is a string containing a name.
-DOMAINS is a list of strings from the fully qualified domain name."
- (or (gnus-picons-lookup-user-internal user domains)
- (gnus-picons-lookup-user-internal "unknown" domains)))
-
-(defun gnus-picons-lookup-pairs (domains directories)
- "Lookup picons for DOMAINS and all its parents in DIRECTORIES.
-Returns a list of PAIRS whose CAR is the picon filename or NIL if
-none, and whose CDR is the corresponding element of DOMAINS."
- (let (picons)
- (setq directories (if (listp directories)
- directories
- (list directories)))
- (while domains
- (push (list (gnus-picons-lookup (cons "unknown" domains) directories)
- (pop domains))
- picons))
- picons))
-
-(defun gnus-picons-display-picon-or-name (picon name &optional right-p)
- (cond (picon (gnus-picons-display-glyph picon name right-p))
- (gnus-picons-display-as-address (list (gnus-picons-make-annotation
- (vector 'string :data name)
- nil 'text
- nil nil nil right-p)))))
-
-(defun gnus-picons-display-pairs (pairs &optional bar-p dot-p right-p)
- "Display picons in list PAIRS."
- (let ((domain-p (and gnus-picons-display-as-address dot-p))
- pair picons)
- (when (and bar-p domain-p right-p
- gnus-picons-display-article-move-p)
- (setq picons (gnus-picons-display-glyph
- (let ((gnus-picons-file-suffixes '("xbm")))
- (gnus-picons-try-face
- gnus-xmas-glyph-directory "bar."))
- nil right-p)))
- (while (setq pair (pop pairs))
- (setq picons (nconc picons
- (gnus-picons-display-picon-or-name
- (car pair) (cadr pair) right-p)
- (if (and domain-p pairs)
- (list (gnus-picons-make-annotation
- (vector 'string :data dot-p)
- nil 'text nil nil nil right-p))))))
- picons))
-
-(defun gnus-picons-try-face (dir &optional filebase)
- (let* ((dir (file-name-as-directory dir))
- (filebase (or filebase "face."))
- (key (concat dir filebase))
- (glyph (cdr (assoc key gnus-picons-glyph-alist)))
- (suffixes gnus-picons-file-suffixes)
- f suf)
- (while (setq suf (pop suffixes))
- (when (file-exists-p (setq f (expand-file-name
- (concat filebase suf)
- dir)))
- (setq suffixes nil
- glyph (make-glyph f))
- (if (equal suf "xbm")
- (set-glyph-face glyph 'gnus-picons-xbm-face)
- (set-glyph-face glyph 'gnus-picons-face))
- (push (cons key glyph) gnus-picons-glyph-alist)))
- glyph))
-
-(defun gnus-picons-display-glyph (glyph &optional part rightp)
- (set-glyph-baseline glyph 70)
- (let ((new (gnus-picons-make-annotation
- glyph (point) 'text nil nil nil rightp)))
- (when (and part gnus-picons-display-as-address)
- (set-annotation-data
- new (cons new (make-glyph (vector 'string :data part))))
- (set-annotation-action new 'gnus-picons-action-toggle))
- (nconc
- (list new)
- (if (and (eq major-mode 'gnus-article-mode)
- (not gnus-picons-display-as-address)
- (not part))
- (list (gnus-picons-make-annotation [string :data " "] (point)
- 'text nil nil nil rightp))))))
-
-(defun gnus-picons-action-toggle (data)
- "Toggle annotation."
- (interactive "e")
- (let* ((annot (car data))
- (glyph (annotation-glyph annot)))
- (set-annotation-glyph annot (cdr data))
- (set-annotation-data annot (cons annot glyph))))
-
-(defun gnus-picons-clear-cache ()
- "Clear the picons cache."
+ (gnus-with-article-buffer
+ (if (memq 'mail-picon gnus-article-wash-types)
+ (gnus-delete-images 'mail-picon)
+ (gnus-picon-transform-address "cc" 'mail-picon)
+ (gnus-picon-transform-address "to" 'mail-picon))))
+
+;;;###autoload
+(defun gnus-treat-newsgroups-picon ()
+ "Display picons in the Newsgroups and Followup-To headers.
+If picons are already displayed, remove them."
(interactive)
- (setq gnus-picons-glyph-alist nil
- gnus-picons-url-alist nil))
-
-(gnus-add-shutdown 'gnus-picons-close 'gnus)
-
-(defun gnus-picons-close ()
- "Shut down the picons."
- (if gnus-picons-clear-cache-on-shutdown
- (gnus-picons-clear-cache)))
-
-;;; Query a remote DB. This requires some stuff from w3 !
-
-(eval-and-compile
- (ignore-errors
- (require 'url)
- (require 'w3-forms)))
-
-(defun gnus-picons-url-retrieve (url fn arg)
- (let ((old-asynch (default-value 'url-be-asynchronous))
- (url-working-buffer (generate-new-buffer " *picons*"))
- (url-package-name "Gnus")
- (url-package-version gnus-version-number)
- url-request-method)
- (setq-default url-be-asynchronous t)
- (save-excursion
- (set-buffer url-working-buffer)
- (setq url-be-asynchronous t
- url-current-callback-data arg
- url-current-callback-func fn)
- (url-retrieve url t))
- (setq-default url-be-asynchronous old-asynch)))
-
-(defun gnus-picons-make-glyph (type)
- "Make a TYPE glyph using current buffer as data. Handles xbm nicely."
- (cond ((null type) nil)
- ((eq type 'xbm) (let ((fname (make-temp-name "/tmp/picon")))
- (write-region (point-min) (point-max) fname
- nil 'quiet)
- (prog1 (make-glyph (vector 'xbm :file fname))
- (delete-file fname))))
- (t (make-glyph (vector type :data (buffer-string))))))
-
-;;; Parsing of piconsearch result page.
-
-;; Assumes:
-;; 1 - each value field has the form: "<strong>key</strong> = <kbd>value</kbd>"
-;; 2 - a "<p>" separates the keywords from the results
-;; 3 - every results begins by the path within the database at the beginning
-;; of the line in raw text.
-;; 3b - and the href following it is the preferred image type.
-
-;; if 1 or 2 is not met, it will probably cause an error. The other
-;; will go undetected
-
-(defun gnus-picons-parse-value (name)
- (goto-char (point-min))
- (if (re-search-forward (concat "<strong>"
- (regexp-quote name)
- "</strong> *= *<kbd> *\\([^ <][^<]*\\) *</kbd>")
- nil t)
- (buffer-substring (match-beginning 1) (match-end 1))))
-
-(defun gnus-picons-parse-filenames ()
- ;; returns an alist of ((USER ADDRS DB) . URL)
- (let ((case-fold-search t)
- (user (gnus-picons-parse-value "user"))
- (host (gnus-picons-parse-value "host"))
- (dbs (message-tokenize-header (gnus-picons-parse-value "db") " "))
- start-re cur-db cur-host cur-user types res)
- ;; now point will be somewhere in the header. Find beginning of
- ;; entries
- (when (and user host dbs)
- (setq start-re
- (concat
- ;; dbs
- "^\\(" (mapconcat 'regexp-quote dbs "\\|") "\\)/"
- ;; host
- "\\(\\(" (mapconcat 'regexp-quote
- (message-tokenize-header host ".") "/\\|")
- "/\\|MISC/\\)*\\)"
- ;; user
- "\\(" (regexp-quote user) "\\|unknown\\)/"
- "face\\."))
- (re-search-forward "<p>[ \t\n]*")
- (while (re-search-forward start-re nil t)
- (setq cur-db (buffer-substring (match-beginning 1) (match-end 1))
- cur-host (buffer-substring (match-beginning 2) (match-end 2))
- cur-user (buffer-substring (match-beginning 4) (match-end 4))
- cur-host (nreverse (message-tokenize-header cur-host "/")))
- ;; XXX - KLUDGE: there is a blank picon in news/MISC/unknown
- (unless (and (string-equal cur-db "news")
- (string-equal cur-user "unknown")
- (equal cur-host '("MISC")))
- ;; ok now we have found an entry (USER HOST DB), find the
- ;; corresponding picon URL
- (save-restriction
- ;; restrict region to this entry
- (narrow-to-region (point) (search-forward "<br>"))
- (goto-char (point-min))
- (setq types gnus-picons-file-suffixes)
- (while (and types
- (not (re-search-forward
- (concat "<a[ \t\n]+href=\"\\([^\"]*\\."
- (regexp-quote (car types)) "\\)\"")
- nil t)))
- (pop types))
- (push (cons (list cur-user cur-host cur-db)
- (buffer-substring (match-beginning 1) (match-end 1)))
- res))))
- (nreverse res))))
-
-;;; picon network display functions :
-
-(defun gnus-picons-network-display-internal (sym-ann glyph part right-p marker)
- (let ((buf (marker-buffer marker))
- (pos (marker-position marker)))
- (if (and buf pos)
- (save-excursion
- (set-buffer buf)
- (goto-char pos)
- (gnus-picons-display-picon-or-name glyph part right-p))))
- (gnus-picons-next-job-internal))
-
-(defun gnus-picons-network-display-callback (url part sym-ann right-p marker)
- (let ((glyph (gnus-picons-make-glyph (cdr (assoc url-current-mime-type
- w3-image-mappings)))))
- (kill-buffer (current-buffer))
- (push (cons url glyph) gnus-picons-glyph-alist)
- ;; only do the job if it has not been preempted.
- (if (equal gnus-picons-job-already-running
- (list sym-ann 'picon url part right-p marker))
- (gnus-picons-network-display-internal
- sym-ann glyph part right-p marker)
- (gnus-picons-next-job-internal))))
-
-(defun gnus-picons-network-display (url part sym-ann right-p marker)
- (let ((cache (assoc url gnus-picons-glyph-alist)))
- (if (or cache (null url))
- (gnus-picons-network-display-internal
- sym-ann (cdr cache) part right-p marker)
- (gnus-picons-url-retrieve url 'gnus-picons-network-display-callback
- (list url part sym-ann right-p marker)))))
-
-;;; search job functions
-
-(defun gnus-picons-display-bar-p ()
- (if (eq gnus-picons-display-where 'article)
- gnus-picons-display-article-move-p
- gnus-picons-display-as-address))
-
-(defun gnus-picons-network-search-internal (user addrs dbs sym-ann right-p
- marker &optional fnames)
- (let (curkey dom pfx url dbs-tmp cache new-jobs)
- ;; First do the domain search
- (dolist (part (if right-p
- (reverse addrs)
- addrs))
- (setq pfx (nconc (list part) pfx)
- dom (cond ((and dom right-p) (concat part "." dom))
- (dom (concat dom "." part))
- (t part))
- curkey (list "unknown" dom dbs))
- (when (null (setq cache (assoc curkey gnus-picons-url-alist)))
- ;; This one is not yet in the cache, create a new entry
- ;; Search for an entry
- (setq dbs-tmp dbs
- url nil)
- (while (and dbs-tmp (null url))
- (setq url (or (cdr (assoc (list "unknown" pfx (car dbs-tmp)) fnames))
- (and (eq dom part)
- ;; This is the first component. Try the
- ;; catch-all MISC component
- (cdr (assoc (list "unknown"
- '("MISC")
- (car dbs-tmp))
- fnames)))))
- (pop dbs-tmp))
- (push (setq cache (cons curkey url)) gnus-picons-url-alist))
- ;; Put this glyph in the job list
- (if (and (not (eq dom part)) gnus-picons-display-as-address)
- (push (list sym-ann "." right-p marker) new-jobs))
- (push (list sym-ann 'picon (cdr cache) part right-p marker) new-jobs))
- ;; next, the user search
- (when user
- (setq curkey (list user dom gnus-picons-user-directories))
- (if (null (setq cache (assoc curkey gnus-picons-url-alist)))
- (let ((users (list user "unknown"))
- dirs usr domains-tmp dir picon)
- (while (and users (null picon))
- (setq dirs gnus-picons-user-directories
- usr (pop users))
- (while (and dirs (null picon))
- (setq domains-tmp addrs
- dir (pop dirs))
- (while (and domains-tmp
- (null (setq picon (assoc (list usr domains-tmp dir)
- fnames))))
- (pop domains-tmp))
- (unless picon
- (setq picon (assoc (list usr '("MISC") dir) fnames)))))
- (push (setq cache (cons curkey (cdr picon)))
- gnus-picons-url-alist)))
- (if (and gnus-picons-display-as-address new-jobs)
- (push (list sym-ann "@" right-p marker) new-jobs))
- (push (list sym-ann 'picon (cdr cache) user right-p marker) new-jobs))
- (if (and (gnus-picons-display-bar-p) (not right-p))
- (push (list sym-ann 'bar right-p marker) new-jobs))
- ;; only put the jobs in the queue if this job has not been preempted.
- (if (equal gnus-picons-job-already-running
- (list sym-ann 'search user addrs dbs right-p marker))
- (setq gnus-picons-jobs-alist
- (nconc (if (and (gnus-picons-display-bar-p) right-p)
- (list (list sym-ann 'bar right-p marker)))
- (nreverse new-jobs)
- gnus-picons-jobs-alist)))
- (gnus-picons-next-job-internal)))
-
-(defun gnus-picons-network-search-callback (user addrs dbs sym-ann right-p
- marker)
- (gnus-picons-network-search-internal
- user addrs dbs sym-ann right-p marker
- (prog1
- (gnus-picons-parse-filenames)
- (kill-buffer (current-buffer)))))
-
-;; Initiate a query on the picon database
-(defun gnus-picons-network-search (user addrs dbs sym-ann right-p marker)
- (let* ((host (mapconcat 'identity addrs "."))
- (key (list (or user "unknown") host (if user
- gnus-picons-user-directories
- dbs)))
- (cache (assoc key gnus-picons-url-alist)))
- (if (null cache)
- (gnus-picons-url-retrieve
- (concat gnus-picons-piconsearch-url
- "?user=" (w3-form-encode-xwfu (or user "unknown"))
- "&host=" (w3-form-encode-xwfu host)
- "&db=" (mapconcat 'w3-form-encode-xwfu
- (if user
- (append dbs
- gnus-picons-user-directories)
- dbs)
- "+"))
- 'gnus-picons-network-search-callback
- (list user addrs dbs sym-ann right-p marker))
- (gnus-picons-network-search-internal
- user addrs dbs sym-ann right-p marker))))
-
-;;; Main jobs dispatcher function
-
-(defun gnus-picons-next-job-internal ()
- (when (setq gnus-picons-job-already-running (pop gnus-picons-jobs-alist))
- (let* ((job gnus-picons-job-already-running)
- (sym-ann (pop job))
- (tag (pop job)))
- (when tag
- (cond
- ((stringp tag);; (SYM-ANN "..." RIGHT-P MARKER)
- (gnus-picons-network-display-internal
- sym-ann nil tag (pop job) (pop job)))
- ((eq 'bar tag);; (SYM-ANN 'bar RIGHT-P MARKER)
- (gnus-picons-network-display-internal
- sym-ann
- (let ((gnus-picons-file-suffixes '("xbm")))
- (gnus-picons-try-face
- gnus-xmas-glyph-directory "bar."))
- nil (pop job) (pop job)))
- ((eq 'search tag);; (SYM-ANN 'search USER ADDRS DBS RIGHT-P MARKER)
- (gnus-picons-network-search
- (pop job) (pop job) (pop job) sym-ann (pop job) (pop job)))
- ((eq 'picon tag);; (SYM-ANN 'picon URL PART RIGHT-P MARKER)
- (gnus-picons-network-display
- (pop job) (pop job) sym-ann (pop job) (pop job)))
- (t
- (setq gnus-picons-job-already-running nil)
- (error "Unknown picon job tag %s" tag)))))))
-
-(defun gnus-picons-next-job ()
- "Start processing the job queue if it is not in progress."
- (unless gnus-picons-job-already-running
- (gnus-picons-next-job-internal)))
+ (gnus-with-article-buffer
+ (if (memq 'newsgroups-picon gnus-article-wash-types)
+ (gnus-delete-images 'newsgroups-picon)
+ (gnus-picon-transform-newsgroups "newsgroups")
+ (gnus-picon-transform-newsgroups "followup-to"))))
(provide 'gnus-picon)
;;; gnus-range.el --- range and sequence functions for Gnus
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;; Keywords: news
range item selector)
(while (or item1 item2)
(setq selector
- (cond
+ (cond
((null item1) nil)
((null item2) t)
((and (numberp item1) (numberp item2)) (< item1 item2))
(setq item
(or
(let ((tmp1 item) (tmp2 (if selector item1 item2)))
- (cond
+ (cond
((null tmp1) tmp2)
((null tmp2) tmp1)
((and (numberp tmp1) (numberp tmp2))
- (cond
+ (cond
((eq tmp1 tmp2) tmp1)
((eq (1+ tmp1) tmp2) (cons tmp1 tmp2))
((eq (1+ tmp2) tmp1) (cons tmp2 tmp1))
(t nil)))
((numberp tmp1)
- (cond
+ (cond
((and (>= tmp1 (car tmp2)) (<= tmp1 (cdr tmp2))) tmp2)
((eq (1+ tmp1) (car tmp2)) (cons tmp1 (cdr tmp2)))
((eq (1- tmp1) (cdr tmp2)) (cons (car tmp2) tmp1))
(t nil)))
((numberp tmp2)
- (cond
+ (cond
((and (>= tmp2 (car tmp1)) (<= tmp2 (cdr tmp1))) tmp1)
((eq (1+ tmp2) (car tmp1)) (cons tmp2 (cdr tmp1)))
((eq (1- tmp2) (cdr tmp1)) (cons (car tmp1) tmp2))
(t nil)))
((< (1+ (cdr tmp1)) (car tmp2)) nil)
((< (1+ (cdr tmp2)) (car tmp1)) nil)
- (t (cons (min (car tmp1) (car tmp2))
+ (t (cons (min (car tmp1) (car tmp2))
(max (cdr tmp1) (cdr tmp2))))))
(progn
(if item (push item range))
;;; gnus-salt.el --- alternate summary mode interfaces for Gnus
-;; Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2001
+;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;; Keywords: news
(require 'gnus)
(require 'gnus-sum)
+(require 'gnus-win)
;;;
;;; gnus-pick-mode
:group 'gnus-summary-pick)
(defcustom gnus-summary-pick-line-format
- "%-5P %U\%R\%z\%I\%(%[%4L: %-20,20n%]%) %s\n"
+ "%-5P %U\%R\%z\%I\%(%[%4L: %-23,23n%]%) %s\n"
"*The format specification of the lines in pick buffers.
It accepts the same format specs that `gnus-summary-line-format' does."
:type 'string
(defun gnus-pick-make-menu-bar ()
(unless (boundp 'gnus-pick-menu)
(easy-menu-define
- gnus-pick-menu gnus-pick-mode-map ""
- '("Pick"
- ("Pick"
- ["Article" gnus-summary-mark-as-processable t]
- ["Thread" gnus-uu-mark-thread t]
- ["Region" gnus-uu-mark-region t]
- ["Regexp" gnus-uu-mark-by-regexp t]
- ["Buffer" gnus-uu-mark-buffer t])
- ("Unpick"
- ["Article" gnus-summary-unmark-as-processable t]
- ["Thread" gnus-uu-unmark-thread t]
- ["Region" gnus-uu-unmark-region t]
- ["Regexp" gnus-uu-unmark-by-regexp t]
- ["Buffer" gnus-summary-unmark-all-processable t])
- ["Start reading" gnus-pick-start-reading t]
- ["Switch pick mode off" gnus-pick-mode gnus-pick-mode]))))
+ gnus-pick-menu gnus-pick-mode-map ""
+ '("Pick"
+ ("Pick"
+ ["Article" gnus-summary-mark-as-processable t]
+ ["Thread" gnus-uu-mark-thread t]
+ ["Region" gnus-uu-mark-region t]
+ ["Regexp" gnus-uu-mark-by-regexp t]
+ ["Buffer" gnus-uu-mark-buffer t])
+ ("Unpick"
+ ["Article" gnus-summary-unmark-as-processable t]
+ ["Thread" gnus-uu-unmark-thread t]
+ ["Region" gnus-uu-unmark-region t]
+ ["Regexp" gnus-uu-unmark-by-regexp t]
+ ["Buffer" gnus-summary-unmark-all-processable t])
+ ["Start reading" gnus-pick-start-reading t]
+ ["Switch pick mode off" gnus-pick-mode gnus-pick-mode]))))
(defun gnus-pick-mode (&optional arg)
"Minor mode for providing a pick-and-read interface in Gnus summary buffers.
(interactive "P")
(if gnus-newsgroup-processable
(progn
- (gnus-summary-limit-to-articles nil)
- (when (or catch-up gnus-mark-unpicked-articles-as-read)
+ (gnus-summary-limit-to-articles nil)
+ (when (or catch-up gnus-mark-unpicked-articles-as-read)
(gnus-summary-limit-mark-excluded-as-read))
- (gnus-summary-first-article)
- (gnus-configure-windows
+ (gnus-summary-first-article)
+ (gnus-configure-windows
(if gnus-pick-display-summary 'article 'pick) t))
(if gnus-pick-elegant-flow
(progn
(let* ((echo-keystrokes 0)
(start-posn (event-start start-event))
(start-point (posn-point start-posn))
- (start-line (1+ (count-lines 1 start-point)))
+ (start-line (1+ (count-lines 1 start-point)))
(start-window (posn-window start-posn))
(bounds (gnus-window-edges start-window))
(top (nth 1 bounds))
(setq mouse-selection-click-count click-count)
(setq mouse-selection-click-count-buffer (current-buffer))
(mouse-set-point start-event)
- ;; In case the down click is in the middle of some intangible text,
+ ;; In case the down click is in the middle of some intangible text,
;; use the end of that text, and put it in START-POINT.
(when (< (point) start-point)
(goto-char start-point))
;; (but not outside the window where the drag started).
(let (event end end-point (end-of-range (point)))
(track-mouse
- (while (progn
- (setq event (cdr (gnus-read-event-char)))
- (or (mouse-movement-p event)
- (eq (car-safe event) 'switch-frame)))
- (if (eq (car-safe event) 'switch-frame)
- nil
- (setq end (event-end event)
- end-point (posn-point end))
-
- (cond
- ;; Are we moving within the original window?
- ((and (eq (posn-window end) start-window)
- (integer-or-marker-p end-point))
- ;; Go to START-POINT first, so that when we move to END-POINT,
- ;; if it's in the middle of intangible text,
- ;; point jumps in the direction away from START-POINT.
- (goto-char start-point)
- (goto-char end-point)
- (gnus-pick-article)
- ;; In case the user moved his mouse really fast, pick
- ;; articles on the line between this one and the last one.
- (let* ((this-line (1+ (count-lines 1 end-point)))
- (min-line (min this-line start-line))
- (max-line (max this-line start-line)))
- (while (< min-line max-line)
- (goto-line min-line)
- (gnus-pick-article)
- (setq min-line (1+ min-line)))
- (setq start-line this-line))
- (when (zerop (% click-count 3))
- (setq end-of-range (point))))
- (t
- (let ((mouse-row (cdr (cdr (mouse-position)))))
- (cond
- ((null mouse-row))
- ((< mouse-row top)
- (mouse-scroll-subr start-window (- mouse-row top)))
- ((>= mouse-row bottom)
- (mouse-scroll-subr start-window
- (1+ (- mouse-row bottom)))))))))))
+ (while (progn
+ (setq event (cdr (gnus-read-event-char)))
+ (or (mouse-movement-p event)
+ (eq (car-safe event) 'switch-frame)))
+ (if (eq (car-safe event) 'switch-frame)
+ nil
+ (setq end (event-end event)
+ end-point (posn-point end))
+
+ (cond
+ ;; Are we moving within the original window?
+ ((and (eq (posn-window end) start-window)
+ (integer-or-marker-p end-point))
+ ;; Go to START-POINT first, so that when we move to END-POINT,
+ ;; if it's in the middle of intangible text,
+ ;; point jumps in the direction away from START-POINT.
+ (goto-char start-point)
+ (goto-char end-point)
+ (gnus-pick-article)
+ ;; In case the user moved his mouse really fast, pick
+ ;; articles on the line between this one and the last one.
+ (let* ((this-line (1+ (count-lines 1 end-point)))
+ (min-line (min this-line start-line))
+ (max-line (max this-line start-line)))
+ (while (< min-line max-line)
+ (goto-line min-line)
+ (gnus-pick-article)
+ (setq min-line (1+ min-line)))
+ (setq start-line this-line))
+ (when (zerop (% click-count 3))
+ (setq end-of-range (point))))
+ (t
+ (let ((mouse-row (cdr (cdr (mouse-position)))))
+ (cond
+ ((null mouse-row))
+ ((< mouse-row top)
+ (mouse-scroll-subr start-window (- mouse-row top)))
+ ((>= mouse-row bottom)
+ (mouse-scroll-subr start-window
+ (1+ (- mouse-row bottom)))))))))))
(when (consp event)
(let ((fun (key-binding (vector (car event)))))
;; Run the binding of the terminating up-event, if possible.
- ;; In the case of a multiple click, it gives the wrong results,
+ ;; In the case of a multiple click, it gives the wrong results,
;; because it would fail to set up a region.
(when nil
- ;; (and (= (mod mouse-selection-click-count 3) 0) (fboundp fun))
- ;; In this case, we can just let the up-event execute normally.
+ ;; (and (= (mod mouse-selection-click-count 3) 0) (fboundp fun))
+ ;; In this case, we can just let the up-event execute normally.
(let ((end (event-end event)))
;; Set the position in the event before we replay it,
;; because otherwise it may have a position in the wrong
;; buffer.
(setcar (cdr end) end-of-range)
;; Delete the overlay before calling the function,
- ;; because delete-overlay increases buffer-modified-tick.
+ ;; because delete-overlay increases buffer-modified-tick.
(push event unread-command-events))))))))
(defun gnus-pick-next-page ()
(defun gnus-binary-make-menu-bar ()
(unless (boundp 'gnus-binary-menu)
(easy-menu-define
- gnus-binary-menu gnus-binary-mode-map ""
- '("Pick"
- ["Switch binary mode off" gnus-binary-mode t]))))
+ gnus-binary-menu gnus-binary-mode-map ""
+ '("Pick"
+ ["Switch binary mode off" gnus-binary-mode t]))))
(defun gnus-binary-mode (&optional arg)
"Minor mode for providing a binary group interface in Gnus summary buffers."
(defun gnus-tree-make-menu-bar ()
(unless (boundp 'gnus-tree-menu)
(easy-menu-define
- gnus-tree-menu gnus-tree-mode-map ""
- '("Tree"
- ["Select article" gnus-tree-select-article t]))))
+ gnus-tree-menu gnus-tree-mode-map ""
+ '("Tree"
+ ["Select article" gnus-tree-select-article t]))))
(defun gnus-tree-mode ()
"Major mode for displaying thread trees."
(defun gnus-tree-recenter ()
"Center point in the tree window."
(let ((selected (selected-window))
- (tree-window (get-buffer-window gnus-tree-buffer t)))
+ (tree-window (gnus-get-buffer-window gnus-tree-buffer t)))
(when tree-window
(select-window tree-window)
(when gnus-selected-tree-overlay
(bottom (save-excursion (goto-char (point-max))
(forward-line (- height))
(point))))
- ;; Set the window start to either `bottom', which is the biggest
+ ;; Set the window start to either `bottom', which is the biggest
;; possible valid number, or the second line from the top,
;; whichever is the least.
(set-window-start
(let* ((score (or (cdr (assq article gnus-newsgroup-scored))
gnus-summary-default-score 0))
(default gnus-summary-default-score)
+ (default-high gnus-summary-default-high-score)
+ (default-low gnus-summary-default-low-score)
(mark (or (gnus-summary-article-mark article) gnus-unread-mark)))
;; Eval the cars of the lists until we find a match.
(while (and list
(gnus-tree-minimize)
(gnus-tree-recenter)
(let ((selected (selected-window)))
- (when (get-buffer-window (set-buffer gnus-tree-buffer) t)
- (select-window (get-buffer-window (set-buffer gnus-tree-buffer) t))
+ (when (gnus-get-buffer-window (set-buffer gnus-tree-buffer) t)
+ (select-window (gnus-get-buffer-window (set-buffer gnus-tree-buffer) t))
(gnus-horizontal-recenter)
(select-window selected))))))
(defun gnus-tree-close (group)
(gnus-kill-buffer gnus-tree-buffer))
+(defun gnus-tree-perhaps-minimize ()
+ (when (and gnus-tree-minimize-window
+ (get-buffer gnus-tree-buffer))
+ (save-excursion
+ (set-buffer gnus-tree-buffer)
+ (gnus-tree-minimize))))
+
(defun gnus-highlight-selected-tree (article)
"Highlight the selected article in the tree."
(let ((buf (current-buffer))
(gnus-tree-minimize)
(gnus-tree-recenter)
(let ((selected (selected-window)))
- (when (get-buffer-window (set-buffer gnus-tree-buffer) t)
- (select-window (get-buffer-window (set-buffer gnus-tree-buffer) t))
+ (when (gnus-get-buffer-window (set-buffer gnus-tree-buffer) t)
+ (select-window (gnus-get-buffer-window (set-buffer gnus-tree-buffer) t))
(gnus-horizontal-recenter)
(select-window selected))))
- ;; If we remove this save-excursion, it updates the wrong mode lines?!?
+;; If we remove this save-excursion, it updates the wrong mode lines?!?
(save-excursion
(set-buffer gnus-tree-buffer)
(gnus-set-mode-line 'tree))
(when (setq region (gnus-tree-article-region article))
(gnus-put-text-property (car region) (cdr region) 'face face)
(set-window-point
- (get-buffer-window (current-buffer) t) (cdr region))))))
+ (gnus-get-buffer-window (current-buffer) t) (cdr region))))))
;;;
;;; gnus-carpal
("matching" . gnus-group-list-matching)
("post" . gnus-group-post-news)
("mail" . gnus-group-mail)
+ ("local" . (lambda () (interactive) (gnus-group-news 0)))
("rescan" . gnus-group-get-new-news)
("browse-foreign" . gnus-group-browse-foreign)
("exit" . gnus-group-exit)))
("kill" . gnus-summary-kill-thread)
"post"
("post" . gnus-summary-post-news)
- ("mail" . gnus-summary-mail)
+ ("local" . gnus-summary-news-other-window)
+ ("mail" . gnus-summary-mail-other-window)
("followup" . gnus-summary-followup-with-original)
("reply" . gnus-summary-reply-with-original)
("cancel" . gnus-summary-cancel-article)
(require 'gnus)
(require 'gnus-sum)
(require 'gnus-range)
+(require 'gnus-win)
(require 'message)
(require 'score-mode)
(setq gnus-global-score-files
'(\"/ftp.gnus.org:/pub/larsi/ding/score/soc.motss.SCORE\"
- \"/ftp.some-where:/pub/score\"))"
+ \"/ftp.some-where:/pub/score\"))"
:group 'gnus-score-files
:type '(repeat file))
If the name of a group is matched by REGEXP, the corresponding scorefiles
will be used for that group.
The first match found is used, subsequent matching entries are ignored (to
-use multiple matches, see gnus-score-file-multiple-match-alist).
+use multiple matches, see `gnus-score-file-multiple-match-alist').
These score files are loaded in addition to any files returned by
-gnus-score-find-score-files-function (which see)."
+`gnus-score-find-score-files-function'."
:group 'gnus-score-files
:type '(repeat (cons regexp (repeat file))))
will be used for that group.
If multiple REGEXPs match a group, the score files corresponding to each
match will be used (for only one match to be used, see
-gnus-score-file-single-match-alist).
+`gnus-score-file-single-match-alist').
These score files are loaded in addition to any files returned by
-gnus-score-find-score-files-function (which see)."
+`gnus-score-find-score-files-function'."
:group 'gnus-score-files
:type '(repeat (cons regexp (repeat file))))
Predefined values are:
-gnus-score-find-single: Only apply the group's own score file.
-gnus-score-find-hierarchical: Also apply score files from parent groups.
-gnus-score-find-bnews: Apply score files whose names matches.
+`gnus-score-find-single': Only apply the group's own score file.
+`gnus-score-find-hierarchical': Also apply score files from parent groups.
+`gnus-score-find-bnews': Apply score files whose names matches.
See the documentation to these functions for more information.
(pop-to-buffer "*Score Help*")
(let ((window-min-height 1))
(shrink-window-if-larger-than-buffer))
- (select-window (get-buffer-window gnus-summary-buffer t))))
+ (select-window (gnus-get-buffer-window gnus-summary-buffer t))))
(defun gnus-summary-header (header &optional no-err extra)
;; Return HEADER for current articles, or error.
(mark-and-expunge (car (gnus-score-get 'mark-and-expunge alist)))
(files (gnus-score-get 'files alist))
(exclude-files (gnus-score-get 'exclude-files alist))
- (orphan (car (gnus-score-get 'orphan alist)))
+ (orphan (car (gnus-score-get 'orphan alist)))
(adapt (gnus-score-get 'adapt alist))
(thread-mark-and-expunge
(car (gnus-score-get 'thread-mark-and-expunge alist)))
(headers gnus-newsgroup-headers)
(current-score-file gnus-current-score-file)
entry header new)
- (gnus-message 5 "Scoring...")
+ (gnus-message 7 "Scoring...")
;; Create articles, an alist of the form `(HEADER . SCORE)'.
(while (setq header (pop headers))
;; WARNING: The assq makes the function O(N*S) while it could
(gnus-score-advanced (car score) trace))
(pop score))))
- (gnus-message 5 "Scoring...done"))))))
+ (gnus-message 7 "Scoring...done"))))))
(defun gnus-score-lower-thread (thread score-adjust)
"Lower the score on THREAD with SCORE-ADJUST.
CHILD2 ...])' where PARENT is a header array and each CHILD is a list
of the same form as THREAD. The empty list `nil' is valid. For each
article in the tree, the score of the corresponding entry in
-GNUS-NEWSGROUP-SCORED is adjusted by SCORE-ADJUST."
+`gnus-newsgroup-scored' is adjusted by SCORE-ADJUST."
(while thread
(let ((head (car thread)))
(if (listp head)
A root is an article with no references. An orphan is an article
which has references, but is not connected via its references to a
root article. This function finds all the orphans, and adjusts their
-score in GNUS-NEWSGROUP-SCORED by SCORE."
+score in `gnus-newsgroup-scored' by SCORE."
;; gnus-make-threads produces a list, where each entry is a "thread"
;; as described in the gnus-score-lower-thread docs. This function
;; will be called again (after limiting has been done) if the display
;; Insert the unique article headers in the buffer.
(let ((gnus-score-index (nth 1 (assoc header gnus-header-index)))
;; gnus-score-index is used as a free variable.
- (simplify (and gnus-score-thread-simplify
- (string= "subject" header)))
+ (simplify (and gnus-score-thread-simplify
+ (string= "subject" header)))
alike last this art entries alist articles
fuzzies arts words kill)
(dmt (downcase mt))
;; Assume user already simplified regexp and fuzzies
(match (if (and simplify (not (memq dmt '(?f ?r))))
- (gnus-map-function
- gnus-simplify-subject-functions
- (nth 0 kill))
- (nth 0 kill)))
+ (gnus-map-function
+ gnus-simplify-subject-functions
+ (nth 0 kill))
+ (nth 0 kill)))
(search-func
(cond ((= dmt ?r) 're-search-forward)
((or (= dmt ?e) (= dmt ?s) (= dmt ?f)) 'search-forward)
;; Evil hackery to make match usable in non-standard headers.
(when extra
(setq match (concat "[ (](" extra " \\. \"[^)]*"
- match "[^(]*\")[ )]")
+ match "[^\"]*\")[ )]")
search-func 're-search-forward)) ; XXX danger?!?
(cond
;; too much.
(delete-char (min (1- (point-max)) klen))
(goto-char (point-max))
- (if (search-backward (string directory-sep-char) nil t)
+ (if (re-search-backward gnus-directory-sep-char-regexp nil t)
(delete-region (1+ (point)) (point-min))
(gnus-message 1 "Can't find directory separator in %s"
(car sfiles))))
;; we add this score file to the list of score files
;; applicable to this group.
(when (or (and not-match
- (ignore-errors
+ (ignore-errors
(not (string-match regexp group-trans))))
- (and (not not-match)
- (ignore-errors (string-match regexp group-trans))))
+ (and (not not-match)
+ (ignore-errors (string-match regexp group-trans))))
(push (car sfiles) ofiles)))
(setq sfiles (cdr sfiles)))
(kill-buffer (current-buffer))
(defun gnus-score-find-alist (group)
"Return list of score files for GROUP.
-The list is determined from the variable gnus-score-file-alist."
+The list is determined from the variable `gnus-score-file-alist'."
(let ((alist gnus-score-file-multiple-match-alist)
score-files)
;; if this group has been seen before, return the cached entry
(while funcs
(when (gnus-functionp (car funcs))
(setq score-files
- (nconc score-files (nreverse (funcall (car funcs) group)))))
+ (append score-files
+ (nreverse (funcall (car funcs) group)))))
(setq funcs (cdr funcs)))
(when gnus-score-use-all-scores
;; Add any home score files.
(when (string-match (gnus-globalify-regexp (car elem)) group)
(replace-match (cadr elem) t nil group))))))
(when found
+ (setq found (nnheader-translate-file-chars found))
(if (file-name-absolute-p found)
- found
- (nnheader-concat gnus-kill-files-directory found)))))
+ found
+ (nnheader-concat gnus-kill-files-directory found)))))
(defun gnus-hierarchial-home-score-file (group)
"Return the score file of the top-level hierarchy of GROUP."
;;; gnus-setup.el --- Initialization & Setup for Gnus 5
-;; Copyright (C) 1995, 1996, 2000 Free Software Foundation, Inc.
+;; Copyright (C) 1995, 1996, 2000, 2001
+;; Free Software Foundation, Inc.
;; Author: Steven L. Baur <steve@miranova.com>
;; Keywords: news
(eval-when-compile (require 'cl))
(defvar gnus-use-installed-gnus t
- "*If non-nil Use installed version of Gnus.")
+ "*If non-nil use installed version of Gnus.")
(defvar gnus-use-installed-mailcrypt (featurep 'xemacs)
"*If non-nil use installed version of mailcrypt.")
--- /dev/null
+;;; gnus-sieve.el --- Utilities to manage sieve scripts for Gnus
+;; Copyright (C) 2001 Free Software Foundation, Inc.
+
+;; Author: NAGY Andras <nagya@inf.elte.hu>,
+;; Simon Josefsson <simon@josefsson.org>
+
+;; This file is not part of GNU Emacs, but the same permissions apply.
+
+;; GNU Emacs 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 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; Gnus glue to generate complete Sieve scripts from Gnus Group
+;; Parameters with "if" test predicates.
+
+;;; Code:
+
+(require 'gnus)
+(require 'gnus-sum)
+(require 'format-spec)
+(autoload 'sieve-mode "sieve-mode")
+(eval-when-compile
+ (require 'sieve))
+
+;; Variables
+
+(defgroup gnus-sieve nil
+ "Manage sieve scripts in Gnus."
+ :group 'gnus)
+
+(defcustom gnus-sieve-file "~/.sieve"
+ "Path to your Sieve script."
+ :type 'file
+ :group 'gnus-sieve)
+
+(defcustom gnus-sieve-region-start "\n## Begin Gnus Sieve Script\n"
+ "Line indicating the start of the autogenerated region in
+your Sieve script."
+ :type 'string
+ :group 'gnus-sieve)
+
+(defcustom gnus-sieve-region-end "\n## End Gnus Sieve Script\n"
+ "Line indicating the end of the autogenerated region in
+your Sieve script."
+ :type 'string
+ :group 'gnus-sieve)
+
+(defcustom gnus-sieve-select-method nil
+ "Which select method we generate the Sieve script for.
+
+For example: \"nnimap:mailbox\""
+ :group 'gnus-sieve)
+
+(defcustom gnus-sieve-crosspost t
+ "Whether the generated Sieve script should do crossposting."
+ :type 'bool
+ :group 'gnus-sieve)
+
+(defcustom gnus-sieve-update-shell-command "echo put %f | sieveshell %s"
+ "Shell command to execute after updating your Sieve script. The following
+formatting characters are recognized:
+
+%f Script's file name (gnus-sieve-file)
+%s Server name (from gnus-sieve-select-method)"
+ :type 'string
+ :group 'gnus-sieve)
+
+;;;###autoload
+(defun gnus-sieve-update ()
+ "Update the Sieve script in gnus-sieve-file, by replacing the region
+between gnus-sieve-region-start and gnus-sieve-region-end with
+\(gnus-sieve-script gnus-sieve-select-method gnus-sieve-crosspost\), then
+execute gnus-sieve-update-shell-command.
+See the documentation for these variables and functions for details."
+ (interactive)
+ (gnus-sieve-generate)
+ (save-buffer)
+ (shell-command
+ (format-spec gnus-sieve-update-shell-command
+ (format-spec-make ?f gnus-sieve-file
+ ?s (or (cadr (gnus-server-get-method
+ nil gnus-sieve-select-method))
+ "")))))
+
+;;;###autoload
+(defun gnus-sieve-generate ()
+ "Generate the Sieve script in gnus-sieve-file, by replacing the region
+between gnus-sieve-region-start and gnus-sieve-region-end with
+\(gnus-sieve-script gnus-sieve-select-method gnus-sieve-crosspost\).
+See the documentation for these variables and functions for details."
+ (interactive)
+ (require 'sieve)
+ (find-file gnus-sieve-file)
+ (goto-char (point-min))
+ (if (re-search-forward
+ (concat (regexp-quote gnus-sieve-region-start) "\\(.\\|\n\\)*"
+ (regexp-quote gnus-sieve-region-end)) nil t)
+ (delete-region (match-beginning 0) (match-end 0))
+ (insert sieve-template))
+ (insert gnus-sieve-region-start
+ (gnus-sieve-script gnus-sieve-select-method gnus-sieve-crosspost)
+ gnus-sieve-region-end))
+
+(defun gnus-sieve-guess-rule-for-article ()
+ "Guess a sieve rule based on RFC822 article in buffer.
+Return nil if no rule could be guessed."
+ (when (message-fetch-field "sender")
+ `(sieve address "sender" ,(regexp-quote (message-fetch-field "sender")))))
+
+;;;###autoload
+(defun gnus-sieve-article-add-rule ()
+ (interactive)
+ (gnus-summary-select-article nil 'force)
+ (with-current-buffer gnus-original-article-buffer
+ (let ((rule (gnus-sieve-guess-rule-for-article))
+ (info (gnus-get-info gnus-newsgroup-name)))
+ (if (null rule)
+ (error "Could not guess rule for article.")
+ (gnus-info-set-params info (cons rule (gnus-info-params info)))
+ (message "Added rule in group %s for article: %s" gnus-newsgroup-name
+ rule)))))
+
+;; Internals
+
+;; FIXME: do proper quoting of " etc
+(defun gnus-sieve-string-list (list)
+ "Convert an elisp string list to a Sieve string list.
+
+For example:
+\(gnus-sieve-string-list '(\"to\" \"cc\"))
+ => \"[\\\"to\\\", \\\"cc\\\"]\"
+"
+ (concat "[\"" (mapconcat 'identity list "\", \"") "\"]"))
+
+(defun gnus-sieve-test-list (list)
+ "Convert an elisp test list to a Sieve test list.
+
+For example:
+\(gnus-sieve-test-list '((address \"sender\" \"boss@company.com\") (size :over 4K)))
+ => \"(address \\\"sender\\\" \\\"boss@company.com\\\", size :over 4K)\""
+ (concat "(" (mapconcat 'gnus-sieve-test list ", ") ")"))
+
+;; FIXME: do proper quoting
+(defun gnus-sieve-test-token (token)
+ "Convert an elisp test token to a Sieve test token.
+
+For example:
+\(gnus-sieve-test-token 'address)
+ => \"address\"
+
+\(gnus-sieve-test-token \"sender\")
+ => \"\\\"sender\\\"\"
+
+\(gnus-sieve-test-token '(\"to\" \"cc\"))
+ => \"[\\\"to\\\", \\\"cc\\\"]\""
+ (cond
+ ((symbolp token) ;; Keyword
+ (symbol-name token))
+
+ ((stringp token) ;; String
+ (concat "\"" token "\""))
+
+ ((and (listp token) ;; String list
+ (stringp (car token)))
+ (gnus-sieve-string-list token))
+
+ ((and (listp token) ;; Test list
+ (listp (car token)))
+ (gnus-sieve-test-list token))))
+
+(defun gnus-sieve-test (test)
+ "Convert an elisp test to a Sieve test.
+
+For example:
+\(gnus-sieve-test '(address \"sender\" \"sieve-admin@extundo.com\"))
+ => \"address \\\"sender\\\" \\\"sieve-admin@extundo.com\\\"\"
+
+\(gnus-sieve-test '(anyof ((header :contains (\"to\" \"cc\") \"my@address.com\")
+ (size :over 100K))))
+ => \"anyof (header :contains [\\\"to\\\", \\\"cc\\\"] \\\"my@address.com\\\",
+ size :over 100K)\""
+ (mapconcat 'gnus-sieve-test-token test " "))
+
+(defun gnus-sieve-script (&optional method crosspost)
+ "Generate a Sieve script based on groups with select method METHOD
+\(or all groups if nil\). Only groups having a `sieve' parameter are
+considered. This parameter should contain an elisp test
+\(see the documentation of gnus-sieve-test for details\). For each
+such group, a Sieve IF control structure is generated, having the
+test as the condition and { fileinto \"group.name\"; } as the body.
+
+If CROSSPOST is nil, each conditional body contains a \"stop\" command
+which stops execution after a match is found.
+
+For example: If the INBOX.list.sieve group has the
+
+ (sieve address \"sender\" \"sieve-admin@extundo.com\")
+
+group parameter, (gnus-sieve-script) results in:
+
+ if address \"sender\" \"sieve-admin@extundo.com\" {
+ fileinto \"INBOX.list.sieve\";
+ }
+
+This is returned as a string."
+ (let* ((newsrc (cdr gnus-newsrc-alist))
+ script)
+ (dolist (info newsrc)
+ (when (or (not method)
+ (gnus-server-equal method (gnus-info-method info)))
+ (let* ((group (gnus-info-group info))
+ (spec (gnus-group-find-parameter group 'sieve t)))
+ (when spec
+ (push (concat "if " (gnus-sieve-test spec) " {\n"
+ "\tfileinto \"" (gnus-group-real-name group) "\";\n"
+ (if gnus-sieve-crosspost
+ ""
+ "\tstop;\n")
+ "}")
+ script)))))
+ (mapconcat 'identity script "\n")))
+
+(provide 'gnus-sieve)
+
+;;; gnus-sieve.el ends here
-;;; gnus-spec.el --- format spec functions for Gnus -*- coding: iso-latin-1 -*-
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;;; gnus-spec.el --- format spec functions for Gnus
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
(require 'gnus)
+(defcustom gnus-use-correct-string-widths t
+ "*If non-nil, use correct functions for dealing with wide characters."
+ :group 'gnus-format
+ :type 'boolean)
+
;;; Internal variables.
(defvar gnus-summary-mark-positions nil)
(defvar gnus-format-specs
`((version . ,emacs-version)
+ (gnus-version . ,(gnus-continuum-version))
(group "%M\%S\%p\%P\%5y: %(%g%)%l\n" ,gnus-group-line-format-spec)
(summary-dummy "* %(: :%) %S\n"
,gnus-summary-dummy-line-format-spec)
- (summary "%U\%R\%z\%I\%(%[%4L: %-20,20n%]%) %s\n"
+ (summary "%U\%R\%z\%I\%(%[%4L: %-23,23n%]%) %s\n"
,gnus-summary-line-format-spec))
"Alist of format specs.")
(defvar gnus-summary-mode-line-format-spec nil)
(defvar gnus-group-mode-line-format-spec nil)
-;;; Phew. All that gruft is over, fortunately.
+;;; Phew. All that gruft is over with, fortunately.
;;;###autoload
(defun gnus-update-format (var)
;; Make the indentation array.
;; See whether all the stored info needs to be flushed.
(when (or force
+ (not (equal (gnus-continuum-version)
+ (cdr (assq 'gnus-version gnus-format-specs))))
(not (equal emacs-version
(cdr (assq 'version gnus-format-specs)))))
(setq gnus-format-specs nil))
;; Go through all the formats and see whether they need updating.
(let (new-format entry type val)
(while (setq type (pop types))
- ;; Jump to the proper buffer to find out the value of
- ;; the variable, if possible. (It may be buffer-local.)
+ ;; Jump to the proper buffer to find out the value of the
+ ;; variable, if possible. (It may be buffer-local.)
(save-excursion
(let ((buffer (intern (format "gnus-%s-buffer" type)))
val)
'balloon-help
,(intern (format "gnus-balloon-face-%d" type))))
+(defun gnus-spec-tab (column)
+ (if (> column 0)
+ `(insert (make-string (max (- ,column (current-column)) 0) ? ))
+ `(progn
+ (if (> (current-column) ,(abs column))
+ (delete-region (point)
+ (- (point) (- (current-column) ,(abs column))))
+ (insert (make-string (max (- ,(abs column) (current-column)) 0)
+ ? ))))))
+
+(defun gnus-correct-length (string)
+ "Return the correct width of STRING."
+ (let ((length 0))
+ (mapcar (lambda (char) (incf length (gnus-char-width char))) string)
+ length))
+
+(defun gnus-correct-substring (string start &optional end)
+ (let ((wstart 0)
+ (wend 0)
+ (wseek 0)
+ (seek 0)
+ (length (length string))
+ (string (concat string "\0")))
+ ;; Find the start position.
+ (while (and (< seek length)
+ (< wseek start))
+ (incf wseek (gnus-char-width (aref string seek)))
+ (incf seek))
+ (setq wstart seek)
+ ;; Find the end position.
+ (while (and (<= seek length)
+ (or (not end)
+ (<= wseek end)))
+ (incf wseek (gnus-char-width (aref string seek)))
+ (incf seek))
+ (setq wend seek)
+ (substring string wstart (1- wend))))
+
(defun gnus-tilde-max-form (el max-width)
"Return a form that limits EL to MAX-WIDTH."
- (let ((max (abs max-width)))
+ (let ((max (abs max-width))
+ (length-fun (if gnus-use-correct-string-widths
+ 'gnus-correct-length
+ 'length))
+ (substring-fun (if gnus-use-correct-string-widths
+ 'gnus-correct-substring
+ 'substring)))
(if (symbolp el)
- `(if (> (length ,el) ,max)
+ `(if (> (,length-fun ,el) ,max)
,(if (< max-width 0)
- `(substring ,el (- (length el) ,max))
- `(substring ,el 0 ,max))
+ `(,substring-fun ,el (- (,length-fun ,el) ,max))
+ `(,substring-fun ,el 0 ,max))
,el)
`(let ((val (eval ,el)))
- (if (> (length val) ,max)
+ (if (> (,length-fun val) ,max)
,(if (< max-width 0)
- `(substring val (- (length val) ,max))
- `(substring val 0 ,max))
+ `(,substring-fun val (- (,length-fun val) ,max))
+ `(,substring-fun val 0 ,max))
val)))))
(defun gnus-tilde-cut-form (el cut-width)
"Return a form that cuts CUT-WIDTH off of EL."
- (let ((cut (abs cut-width)))
+ (let ((cut (abs cut-width))
+ (length-fun (if gnus-use-correct-string-widths
+ 'gnus-correct-length
+ 'length))
+ (substring-fun (if gnus-use-correct-string-widths
+ 'gnus-correct-substring
+ 'substring)))
(if (symbolp el)
- `(if (> (length ,el) ,cut)
+ `(if (> (,length-fun ,el) ,cut)
,(if (< cut-width 0)
- `(substring ,el 0 (- (length el) ,cut))
- `(substring ,el ,cut))
+ `(,substring-fun ,el 0 (- (,length-fun ,el) ,cut))
+ `(,substring-fun ,el ,cut))
,el)
`(let ((val (eval ,el)))
- (if (> (length val) ,cut)
+ (if (> (,length-fun val) ,cut)
,(if (< cut-width 0)
- `(substring val 0 (- (length val) ,cut))
- `(substring val ,cut))
+ `(,substring-fun val 0 (- (,length-fun val) ,cut))
+ `(,substring-fun val ,cut))
val)))))
(defun gnus-tilde-ignore-form (el ignore-value)
(if (equal val ,ignore-value)
"" val))))
+(defun gnus-correct-pad-form (el pad-width)
+ "Return a form that pads EL to PAD-WIDTH accounting for multi-column
+characters correctly. This is because `format' may pad to columns or to
+characters when given a pad value."
+ (let ((pad (abs pad-width))
+ (side (< 0 pad-width)))
+ (if (symbolp el)
+ `(let ((need (- ,pad (gnus-correct-length ,el))))
+ (if (> need 0)
+ (concat ,(when side '(make-string need ?\ ))
+ ,el
+ ,(when (not side) '(make-string need ?\ )))
+ ,el))
+ `(let* ((val (eval ,el))
+ (need (- ,pad (gnus-correct-length ,el))))
+ (if (> need 0)
+ (concat ,(when side '(make-string need ?\ ))
+ ,el
+ ,(when (not side) '(make-string need ?\ )))
+ ,el)))))
+
(defun gnus-parse-format (format spec-alist &optional insert)
;; This function parses the FORMAT string with the help of the
;; SPEC-ALIST and returns a list that can be eval'ed to return the
;; the text between them will have the mouse-face text property.
;; If the FORMAT string contains the specifiers %[ and %], the text between
;; them will have the balloon-help text property.
- (if (string-match
+ (let ((case-fold-search nil))
+ (if (string-match
"\\`\\(.*\\)%[0-9]?[{(«]\\(.*\\)%[0-9]?[»})]\\(.*\n?\\)\\'"
format)
(gnus-parse-complex-format format spec-alist)
- ;; This is a simple format.
- (gnus-parse-simple-format format spec-alist insert)))
+ ;; This is a simple format.
+ (gnus-parse-simple-format format spec-alist insert))))
(defun gnus-parse-complex-format (format spec-alist)
- (save-excursion
- (gnus-set-work-buffer)
- (insert format)
- (goto-char (point-min))
- (while (re-search-forward "\"" nil t)
- (replace-match "\\\"" nil t))
- (goto-char (point-min))
- (insert "(\"")
- (while (re-search-forward "%\\([0-9]+\\)?\\([«»{}()]\\)" nil t)
- (let ((number (if (match-beginning 1)
- (match-string 1) "0"))
- (delim (aref (match-string 2) 0)))
- (if (or (= delim ?\()
- (= delim ?\{)
- (= delim ?\«))
- (replace-match (concat "\"("
- (cond ((= delim ?\() "mouse")
- ((= delim ?\{) "face")
- (t "balloon"))
- " " number " \""))
- (replace-match "\")\""))))
- (goto-char (point-max))
- (insert "\")")
- (goto-char (point-min))
- (let ((form (read (current-buffer))))
- (cons 'progn (gnus-complex-form-to-spec form spec-alist)))))
+ (let (found-C)
+ (save-excursion
+ (gnus-set-work-buffer)
+ (insert format)
+ (goto-char (point-min))
+ (while (re-search-forward "\"" nil t)
+ (replace-match "\\\"" nil t))
+ (goto-char (point-min))
+ (insert "(\"")
+ ;; Convert all font specs into font spec lists.
+ (while (re-search-forward "%\\([0-9]+\\)?\\([«»{}()]\\)" nil t)
+ (let ((number (if (match-beginning 1)
+ (match-string 1) "0"))
+ (delim (aref (match-string 2) 0)))
+ (if (or (= delim ?\()
+ (= delim ?\{)
+ (= delim ?\«))
+ (replace-match (concat "\"("
+ (cond ((= delim ?\() "mouse")
+ ((= delim ?\{) "face")
+ (t "balloon"))
+ " " number " \"")
+ t t)
+ (replace-match "\")\""))))
+ (goto-char (point-max))
+ (insert "\")")
+ ;; Convert point position commands.
+ (goto-char (point-min))
+ (let ((case-fold-search nil))
+ (while (re-search-forward "%\\([-0-9]+\\)?C" nil t)
+ (replace-match "\"(point)\"" t t)
+ (setq found-C t)))
+ ;; Convert TAB commands.
+ (goto-char (point-min))
+ (while (re-search-forward "%\\([-0-9]+\\)=" nil t)
+ (replace-match (format "\"(tab %s)\"" (match-string 1)) t t))
+ ;; Convert the buffer into the spec.
+ (goto-char (point-min))
+ (let ((form (read (current-buffer))))
+ (if found-C
+ `(let (gnus-position)
+ ,@(gnus-complex-form-to-spec form spec-alist)
+ (if gnus-position
+ (gnus-put-text-property gnus-position (1+ gnus-position)
+ 'gnus-position t)))
+ `(progn
+ ,@(gnus-complex-form-to-spec form spec-alist)))))))
(defun gnus-complex-form-to-spec (form spec-alist)
(delq nil
(mapcar
(lambda (sform)
- (if (stringp sform)
- (gnus-parse-simple-format sform spec-alist t)
+ (cond
+ ((stringp sform)
+ (gnus-parse-simple-format sform spec-alist t))
+ ((eq (car sform) 'point)
+ '(setq gnus-position (point)))
+ ((eq (car sform) 'tab)
+ (gnus-spec-tab (cadr sform)))
+ (t
(funcall (intern (format "gnus-%s-face-function" (car sform)))
(gnus-complex-form-to-spec (cddr sform) spec-alist)
- (nth 1 sform))))
+ (nth 1 sform)))))
form)))
(defun gnus-parse-simple-format (format spec-alist &optional insert)
(let ((max-width 0)
spec flist fstring elem result dontinsert user-defined
type value pad-width spec-beg cut-width ignore-value
- tilde-form tilde elem-type)
+ tilde-form tilde elem-type extended-spec)
(save-excursion
(gnus-set-work-buffer)
(insert format)
max-width nil
cut-width nil
ignore-value nil
- tilde-form nil)
+ tilde-form nil
+ extended-spec nil)
(setq spec-beg (1- (point)))
;; Parse this spec fully.
t)
(t
nil)))
- ;; User-defined spec -- find the spec name.
- (when (eq (setq spec (char-after)) ?u)
+ (cond
+ ;; User-defined spec -- find the spec name.
+ ((eq (setq spec (char-after)) ?u)
(forward-char 1)
- (setq user-defined (char-after)))
+ (when (and (eq (setq user-defined (char-after)) ?&)
+ (looking-at "&\\([^;]+\\);"))
+ (setq user-defined (match-string 1))
+ (goto-char (match-end 1))))
+ ;; extended spec
+ ((and (eq spec ?&) (looking-at "&\\([^;]+\\);"))
+ (setq extended-spec (intern (match-string 1)))
+ (goto-char (match-end 1))))
(forward-char 1)
(delete-region spec-beg (point))
(user-defined
(setq elem
(list
- (list (intern (format "gnus-user-format-function-%c"
- user-defined))
+ (list (intern (format
+ (if (stringp user-defined)
+ "gnus-user-format-function-%s"
+ "gnus-user-format-function-%c")
+ user-defined))
'gnus-tmp-header)
?s)))
;; Find the specification from `spec-alist'.
- ((setq elem (cdr (assq spec spec-alist))))
+ ((setq elem (cdr (assq (or extended-spec spec) spec-alist))))
(t
(setq elem '("*" ?s))))
(setq elem-type (cadr elem))
;; Insert the new format elements.
- (when pad-width
+ (when (and pad-width
+ (not (and (featurep 'xemacs)
+ gnus-use-correct-string-widths)))
(insert (number-to-string pad-width)))
;; Create the form to be evaled.
- (if (or max-width cut-width ignore-value)
+ (if (or max-width cut-width ignore-value
+ (and (featurep 'xemacs)
+ gnus-use-correct-string-widths))
(progn
(insert ?s)
(let ((el (car elem)))
(setq el (gnus-tilde-cut-form el cut-width)))
(when max-width
(setq el (gnus-tilde-max-form el max-width)))
+ (when pad-width
+ (setq el (gnus-correct-pad-form el pad-width)))
(push el flist)))
(insert elem-type)
(push (car elem) flist))))
- (setq fstring (buffer-string)))
+ (setq fstring (buffer-substring-no-properties (point-min) (point-max))))
;; Do some postprocessing to increase efficiency.
(setq
result
(cond
- ;; Emptyness.
+ ;; Emptiness.
((string= fstring "")
nil)
;; Not a format string.
(while entries
(setq entry (pop entries))
- (if (eq (car entry) 'version)
+ (if (memq (car entry) '(gnus-version version))
(setq gnus-format-specs (delq entry gnus-format-specs))
(let ((form (caddr entry)))
(when (and (listp form)
(require 'gnus-int)
(require 'gnus-range)
-(defvar gnus-server-mode-hook nil
- "Hook run in `gnus-server-mode' buffers.")
+(defcustom gnus-server-mode-hook nil
+ "Hook run in `gnus-server-mode' buffers."
+ :group 'gnus-server
+ :type 'hook)
-(defconst gnus-server-line-format " {%(%h:%w%)} %s%a\n"
+(defcustom gnus-server-exit-hook nil
+ "Hook run when exiting the server buffer."
+ :group 'gnus-server
+ :type 'hook)
+
+(defcustom gnus-server-line-format " {%(%h:%w%)} %s%a\n"
"Format of server lines.
It works along the same lines as a normal formatting string,
with some simple extensions.
%n name
%w address
%s status
-%a agent covered")
-
-(defvar gnus-server-mode-line-format "Gnus: %%b"
- "The format specification for the server mode line.")
+%a agent covered"
+ :group 'gnus-server-visual
+ :type 'string)
-(defvar gnus-server-exit-hook nil
- "*Hook run when exiting the server buffer.")
+(defcustom gnus-server-mode-line-format "Gnus: %%b"
+ "The format specification for the server mode line."
+ :group 'gnus-server-visual
+ :type 'string)
-(defvar gnus-server-browse-in-group-buffer t
- "Whether browse server in group buffer.")
+(defcustom gnus-server-browse-in-group-buffer nil
+ "Whether server browsing should take place in the group buffer.
+If nil, a faster, but more primitive, buffer is used instead."
+ :group 'gnus-server-visual
+ :type 'string)
;;; Internal variables.
"\C-c\C-i" gnus-info-find-node
"\C-c\C-b" gnus-bug))
+(defface gnus-server-agent-face
+ '((((class color) (background light)) (:foreground "PaleTurquoise" :bold t))
+ (((class color) (background dark)) (:foreground "PaleTurquoise" :bold t))
+ (t (:bold t)))
+ "Face used for displaying AGENTIZED servers"
+ :group 'gnus-server-visual)
+
+(defface gnus-server-opened-face
+ '((((class color) (background light)) (:foreground "Green3" :bold t))
+ (((class color) (background dark)) (:foreground "Green1" :bold t))
+ (t (:bold t)))
+ "Face used for displaying OPENED servers"
+ :group 'gnus-server-visual)
+
+(defface gnus-server-closed-face
+ '((((class color) (background light)) (:foreground "Steel Blue" :italic t))
+ (((class color) (background dark))
+ (:foreground "Light Steel Blue" :italic t))
+ (t (:italic t)))
+ "Face used for displaying CLOSED servers"
+ :group 'gnus-server-visual)
+
+(defface gnus-server-denied-face
+ '((((class color) (background light)) (:foreground "Red" :bold t))
+ (((class color) (background dark)) (:foreground "Pink" :bold t))
+ (t (:inverse-video t :bold t)))
+ "Face used for displaying DENIED servers"
+ :group 'gnus-server-visual)
+
+(defcustom gnus-server-agent-face 'gnus-server-agent-face
+ "Face name to use on AGENTIZED servers."
+ :group 'gnus-server-visual
+ :type 'face)
+
+(defcustom gnus-server-opened-face 'gnus-server-opened-face
+ "Face name to use on OPENED servers."
+ :group 'gnus-server-visual
+ :type 'face)
+
+(defcustom gnus-server-closed-face 'gnus-server-closed-face
+ "Face name to use on CLOSED servers."
+ :group 'gnus-server-visual
+ :type 'face)
+
+(defcustom gnus-server-denied-face 'gnus-server-denied-face
+ "Face name to use on DENIED servers."
+ :group 'gnus-server-visual
+ :type 'face)
+
+(defvar gnus-server-font-lock-keywords
+ (list
+ '("(\\(agent\\))" 1 gnus-server-agent-face)
+ '("(\\(opened\\))" 1 gnus-server-opened-face)
+ '("(\\(closed\\))" 1 gnus-server-closed-face)
+ '("(\\(denied\\))" 1 gnus-server-denied-face)))
+
(defun gnus-server-mode ()
"Major mode for listing and editing servers.
All normal editing commands are switched off.
\\<gnus-server-mode-map>
For more in-depth information on this mode, read the manual
-(`\\[gnus-info-find-node]').
+\(`\\[gnus-info-find-node]').
The following commands are available:
(buffer-disable-undo)
(setq truncate-lines t)
(setq buffer-read-only t)
+ (if (featurep 'xemacs)
+ (put 'gnus-server-mode 'font-lock-defaults '(gnus-server-font-lock-keywords t))
+ (set (make-local-variable 'font-lock-defaults)
+ '(gnus-server-font-lock-keywords t)))
(gnus-run-hooks 'gnus-server-mode-hook))
(defun gnus-server-insert-server-line (gnus-tmp-name method)
(let* ((gnus-tmp-how (car method))
(gnus-tmp-where (nth 1 method))
(elem (assoc method gnus-opened-servers))
- (gnus-tmp-status (cond ((eq (nth 1 elem) 'denied)
- "(denied)")
- ((or (gnus-server-opened method)
- (eq (nth 1 elem) 'ok))
- "(opened)")
- (t
- "(closed)")))
+ (gnus-tmp-status
+ (if (eq (nth 1 elem) 'denied)
+ "(denied)"
+ (condition-case nil
+ (if (or (gnus-server-opened method)
+ (eq (nth 1 elem) 'ok))
+ "(opened)"
+ "(closed)")
+ ((error) "(error)"))))
(gnus-tmp-agent (if (and gnus-agent
(member method
gnus-agent-covered-methods))
["Read" gnus-browse-read-group t]
["Select" gnus-browse-select-group t]
["Next" gnus-browse-next-group t]
- ["Prev" gnus-browse-next-group t]
+ ["Prev" gnus-browse-prev-group t]
["Exit" gnus-browse-exit t]))
(gnus-run-hooks 'gnus-browse-menu-hook)))
groups)))
(gnus-configure-windows 'group)
(funcall gnus-group-prepare-function
- gnus-level-killed 'ignore 1 'ingore))
+ gnus-level-killed 'ignore 1 'ignore))
(gnus-get-buffer-create gnus-browse-buffer)
(when gnus-carpal
(gnus-carpal-setup-buffer 'browse))
(list
(format
"Gnus: %%b {%s:%s}" (car method) (cadr method))))
- (let ((buffer-read-only nil) charset)
+ (let ((buffer-read-only nil) charset
+ (prefix (let ((gnus-select-method orig-select-method))
+ (gnus-group-prefixed-name "" method))))
(while groups
(setq group (car groups))
- (setq charset (gnus-group-name-charset method group))
+ (setq charset (gnus-group-name-charset method (car group)))
(gnus-add-text-properties
(point)
(prog1 (1+ (point))
(insert
(format "%c%7d: %s\n"
- (let ((level
- (let ((gnus-select-method orig-select-method))
- (gnus-group-level
- (gnus-group-prefixed-name (car group)
- method)))))
+ (let ((level (gnus-group-level (concat prefix (car group)))))
(cond
((<= level gnus-level-subscribed) ? )
((<= level gnus-level-unsubscribed) ?U)
(unless server
(error "No server on the current line"))
(condition-case ()
- (gnus-get-function (gnus-server-to-method server)
+ (gnus-get-function (gnus-server-to-method server)
'request-regenerate)
(error
(error "This backend doesn't support regeneration")))
(provide 'gnus-srvr)
-;;; gnus-srvr.el ends here.
+;;; gnus-srvr.el ends here
(defcustom gnus-ignored-newsgroups
(mapconcat 'identity
'("^to\\." ; not "real" groups
- "^[0-9. \t]+ " ; all digits in name
+ "^[0-9. \t]+\\( \\|$\\)" ; all digits in name
"^[\"][]\"[#'()]" ; bogus characters
)
"\\|")
:type 'boolean)
(defcustom gnus-auto-subscribed-groups
- "nnml\\|^nnfolder\\|^nnmbox\\|^nnmh\\|^nnbabyl"
+ "^nnml\\|^nnfolder\\|^nnmbox\\|^nnmh\\|^nnbabyl"
"*All new groups that match this regexp will be subscribed automatically.
Note that this variable only deals with new groups. It has no effect
whatsoever on old groups.
:group 'gnus-newsrc
:type 'hook)
+(defcustom gnus-group-mode-hook nil
+ "Hook for Gnus group mode."
+ :group 'gnus-group-various
+ :options '(gnus-topic-mode)
+ :type 'hook)
+
(defcustom gnus-always-read-dribble-file nil
"Unconditionally read the dribble file."
:group 'gnus-newsrc
:type 'boolean)
+;;; Internal variables
+
(defvar gnus-startup-file-coding-system 'binary
"*Coding system for startup file.")
-;;; Internal variables
+(defvar gnus-ding-file-coding-system mm-universal-coding-system
+ "*Coding system for ding file.")
(defvar gnus-newsrc-file-version nil)
(defvar gnus-override-subscribe-method nil)
(not (file-directory-p file)))
(file-exists-p (concat file ".el"))
(file-exists-p (concat file ".elc")))
- (condition-case var
+ (if (or debug-on-error debug-on-quit)
(let ((coding-system-for-read
gnus-startup-file-coding-system))
(load file nil t))
- (error
- (error "Error in %s: %s" file var)))))))))
+ (condition-case var
+ (let ((coding-system-for-read
+ gnus-startup-file-coding-system))
+ (load file nil t))
+ (error
+ (error "Error in %s: %s" file var))))))))))
;; For subscribing new newsgroup
;; Make sure the archive server is available to all and sundry.
(when gnus-message-archive-method
- (setq gnus-server-alist (delq (assoc "archive" gnus-server-alist)
- gnus-server-alist))
- (push (cons "archive" gnus-message-archive-method)
- gnus-server-alist))
+ (unless (assoc "archive" gnus-server-alist)
+ (push `("archive"
+ nnfolder
+ "archive"
+ (nnfolder-directory
+ ,(nnheader-concat message-directory "archive"))
+ (nnfolder-active-file
+ ,(nnheader-concat message-directory "archive/active"))
+ (nnfolder-get-new-mail nil)
+ (nnfolder-inhibit-expiry t))
+ gnus-server-alist)))
;; If we don't read the complete active file, we fill in the
;; hashtb here.
gnus-plugged)
(gnus-find-new-newsgroups))
+ ;; Check and remove bogus newsgroups.
+ (when (and init gnus-check-bogus-newsgroups
+ gnus-read-active-file (not level)
+ (gnus-server-opened gnus-select-method))
+ (gnus-check-bogus-newsgroups))
+
;; We might read in new NoCeM messages here.
(when (and gnus-use-nocem
(not level)
;; Find the number of unread articles in each non-dead group.
(let ((gnus-read-active-file (and (not level) gnus-read-active-file)))
- (gnus-get-unread-articles level))
-
- (when (and init gnus-check-bogus-newsgroups
- gnus-read-active-file (not level)
- (gnus-server-opened gnus-select-method))
- (gnus-check-bogus-newsgroups))))
+ (gnus-get-unread-articles level))))
(defun gnus-call-subscribe-functions (method group)
"Call METHOD to subscribe GROUP.
(gnus-message 5 "Looking for new newsgroups...")
(unless gnus-have-read-active-file
(gnus-read-active-file))
- (setq gnus-newsrc-last-checked-date (current-time-string))
+ (setq gnus-newsrc-last-checked-date (message-make-date))
(unless gnus-killed-hashtb
(gnus-make-hashtable-from-killed))
;; Go though every newsgroup in `gnus-active-hashtb' and compare
(and regs (cdar regs))))))
(defun gnus-ask-server-for-new-groups ()
- (let* ((date (or gnus-newsrc-last-checked-date (current-time-string)))
+ (let* ((new-date (message-make-date))
+ (date (or gnus-newsrc-last-checked-date new-date))
(methods (cons gnus-select-method
(nconc
(when (gnus-archive-server-wanted-p)
gnus-check-new-newsgroups)
gnus-secondary-select-methods))))
(groups 0)
- (new-date (current-time-string))
group new-newsgroups got-new method hashtb
gnus-override-subscribe-method)
(unless gnus-killed-hashtb
(catch 'ended
;; First check if any of the following files exist. If they do,
;; it's not the first time the user has used Gnus.
- (dolist (file (list gnus-current-startup-file
- (concat gnus-current-startup-file ".el")
+ (dolist (file (list (concat gnus-current-startup-file ".el")
(concat gnus-current-startup-file ".eld")
- gnus-startup-file
(concat gnus-startup-file ".el")
(concat gnus-startup-file ".eld")))
(when (file-exists-p file)
(unless (gnus-read-active-file-p)
(let ((gnus-read-active-file t))
(gnus-read-active-file)))
- (setq gnus-newsrc-last-checked-date (current-time-string))
+ (setq gnus-newsrc-last-checked-date (message-make-date))
;; Subscribe to the default newsgroups.
(let ((groups (or gnus-default-subscribed-newsgroups
gnus-backup-default-subscribed-newsgroups))
group)
- (when (eq groups t)
- ;; If t, we subscribe (or not) all groups as if they were new.
- (mapatoms
- (lambda (sym)
- (when (setq group (symbol-name sym))
- (let ((do-sub (gnus-matches-options-n group)))
- (cond
- ((eq do-sub 'subscribe)
- (gnus-sethash group group gnus-killed-hashtb)
- (gnus-call-subscribe-functions
- gnus-subscribe-options-newsgroup-method group))
- ((eq do-sub 'ignore)
- nil)
- (t
- (push group gnus-killed-list))))))
- gnus-active-hashtb)
+ (if (eq groups t)
+ ;; If t, we subscribe (or not) all groups as if they were new.
+ (mapatoms
+ (lambda (sym)
+ (when (setq group (symbol-name sym))
+ (let ((do-sub (gnus-matches-options-n group)))
+ (cond
+ ((eq do-sub 'subscribe)
+ (gnus-sethash group group gnus-killed-hashtb)
+ (gnus-call-subscribe-functions
+ gnus-subscribe-options-newsgroup-method group))
+ ((eq do-sub 'ignore)
+ nil)
+ (t
+ (push group gnus-killed-list))))))
+ gnus-active-hashtb)
(dolist (group groups)
;; Only subscribe the default groups that are activated.
(when (gnus-active group)
group gnus-level-default-subscribed gnus-level-killed)))
(save-excursion
(set-buffer gnus-group-buffer)
- (gnus-group-make-help-group))
+ ;; Don't error if the group already exists. This happens when a
+ ;; first-time user types 'F'. -- didier
+ (gnus-group-make-help-group t))
(when gnus-novice-user
(gnus-message 7 "`A k' to list killed groups"))))))
(setq info (pop newsrc)
group (gnus-info-group info))
(unless (or (gnus-active group) ; Active
- (gnus-info-method info)) ; Foreign
+ (and (gnus-info-method info)
+ (not (gnus-secondary-method-p
+ (gnus-info-method info))))) ; Foreign
;; Found a bogus newsgroup.
(push group bogus)))
(if confirm
(gnus-check-backend-function 'request-scan (car method))
(gnus-request-scan group method))
t)
- (condition-case ()
+ (if (or debug-on-error debug-on-quit)
(inline (gnus-request-group group dont-check method))
- ;;(error nil)
- (quit
- (message "Quit activating %s" group)
- nil))
- (setq active (gnus-parse-active))
- ;; If there are no articles in the group, the GROUP
- ;; command may have responded with the `(0 . 0)'. We
- ;; ignore this if we already have an active entry
- ;; for the group.
- (if (and (zerop (car active))
- (zerop (cdr active))
- (gnus-active group))
- (gnus-active group)
- (gnus-set-active group active)
- ;; Return the new active info.
- active))))
+ (condition-case ()
+ (inline (gnus-request-group group dont-check method))
+ ;;(error nil)
+ (quit
+ (message "Quit activating %s" group)
+ nil)))
+ (unless dont-check
+ (setq active (gnus-parse-active))
+ ;; If there are no articles in the group, the GROUP
+ ;; command may have responded with the `(0 . 0)'. We
+ ;; ignore this if we already have an active entry
+ ;; for the group.
+ (if (and (zerop (car active))
+ (zerop (cdr active))
+ (gnus-active group))
+ (gnus-active group)
+ (gnus-set-active group active)
+ ;; Return the new active info.
+ active)))))
(defun gnus-get-unread-articles-in-group (info active &optional update)
(when active
(not (gnus-secondary-method-p method)))
;; These groups are foreign. Check the level.
(when (and (<= (gnus-info-level info) foreign-level)
- (setq active (gnus-activate-group group 'scan)))
+ (setq active (gnus-activate-group group 'scan)))
;; Let the Gnus agent save the active file.
(when (and gnus-agent gnus-plugged active)
(gnus-agent-save-group-info
(setq active (gnus-activate-group group))
(setq active (gnus-activate-group group 'scan))
(push method scanned-methods))
- (when active
- (gnus-close-group group))))))
+ (when active
+ (gnus-close-group group))))))
;; Get the number of unread articles in the group.
(cond
(let ((method (or (car rg) gnus-select-method))
(groups (cdr rg)))
(when (gnus-check-server method)
- ;; Request that the backend scan its incoming messages.
- (when (gnus-check-backend-function 'request-scan (car method))
- (gnus-request-scan nil method))
- (gnus-read-active-file-2
+ ;; Request that the backend scan its incoming messages.
+ (when (gnus-check-backend-function 'request-scan (car method))
+ (gnus-request-scan nil method))
+ (gnus-read-active-file-2
(mapcar (lambda (group) (gnus-group-real-name group)) groups)
method)
- (dolist (group groups)
- (cond
- ((setq active (gnus-active (gnus-info-group
- (setq info (gnus-get-info group)))))
- (inline (gnus-get-unread-articles-in-group info active t)))
- (t
- ;; The group couldn't be reached, so we nix out the number of
- ;; unread articles and stuff.
- (gnus-set-active group nil)
- (setcar (gnus-gethash group gnus-newsrc-hashtb) t)))))))
+ (dolist (group groups)
+ (cond
+ ((setq active (gnus-active (gnus-info-group
+ (setq info (gnus-get-info group)))))
+ (inline (gnus-get-unread-articles-in-group info active t)))
+ (t
+ ;; The group couldn't be reached, so we nix out the number of
+ ;; unread articles and stuff.
+ (gnus-set-active group nil)
+ (setcar (gnus-gethash group gnus-newsrc-hashtb) t)))))))
(gnus-message 5 "Checking new news...done")))
;; Only do each method once, in case the methods appear more
;; than once in this list.
(unless (member method methods)
- (condition-case ()
+ (if (or debug-on-error debug-on-quit)
(gnus-read-active-file-1 method force)
- ;; We catch C-g so that we can continue past servers
- ;; that do not respond.
- (quit
- (message "Quit reading the active file")
- nil)))))))
+ (condition-case ()
+ (gnus-read-active-file-1 method force)
+ ;; We catch C-g so that we can continue past servers
+ ;; that do not respond.
+ (quit
+ (message "Quit reading the active file")
+ nil))))))))
(defun gnus-read-active-file-1 (method force)
(let (where mesg)
;; We always, always read the .eld file.
(gnus-message 5 "Reading %s..." ding-file)
(let (gnus-newsrc-assoc)
- (condition-case nil
- (let ((coding-system-for-read gnus-startup-file-coding-system))
+ (if (or debug-on-error debug-on-quit)
+ (let ((coding-system-for-read gnus-ding-file-coding-system))
(load ding-file t t t))
- (error
- (ding)
- (unless (gnus-yes-or-no-p
- (format "Error in %s; continue? " ding-file))
- (error "Error in %s" ding-file))))
+ (condition-case nil
+ (let ((coding-system-for-read gnus-ding-file-coding-system))
+ (load ding-file t t t))
+ (error
+ (ding)
+ (unless (gnus-yes-or-no-p
+ (format "Error in %s; continue? " ding-file))
+ (error "Error in %s" ding-file)))))
;; Older versions of `gnus-format-specs' are no longer valid
;; in Oort Gnus 0.01.
- (let ((version
+ (let ((version
(and gnus-newsrc-file-version
(gnus-continuum-version gnus-newsrc-file-version))))
(when (or (not version)
(gnus-message 5 "Saving %s.eld..." gnus-current-startup-file)
(gnus-gnus-to-quick-newsrc-format)
(gnus-run-hooks 'gnus-save-quick-newsrc-hook)
- (let ((coding-system-for-write gnus-startup-file-coding-system))
+ (let ((coding-system-for-write gnus-ding-file-coding-system))
(save-buffer))
(kill-buffer (current-buffer))
(gnus-message
(make-temp-name (concat gnus-current-startup-file "-slave-")))
(modes (ignore-errors
(file-modes (concat gnus-current-startup-file ".eld")))))
- (let ((coding-system-for-write gnus-startup-file-coding-system))
+ (let ((coding-system-for-write gnus-ding-file-coding-system))
(gnus-write-buffer slave-name))
(when modes
(set-file-modes slave-name modes)))))
(require 'gnus-undo)
(require 'gnus-util)
(require 'mm-decode)
-;; Recursive :-(.
-;; (require 'gnus-art)
(require 'nnoo)
+
(autoload 'gnus-summary-limit-include-cached "gnus-cache" nil t)
(autoload 'gnus-cache-write-active "gnus-cache")
(autoload 'gnus-mailing-list-insinuate "gnus-ml" nil t)
:type '(choice (const :tag "disable")
integer))
+(defcustom gnus-summary-default-high-score 0
+ "*Default threshold for a high scored article.
+An article will be highlighted as high scored if its score is greater
+than this score."
+ :group 'gnus-score-default
+ :type 'integer)
+
+(defcustom gnus-summary-default-low-score 0
+ "*Default threshold for a low scored article.
+An article will be highlighted as low scored if its score is smaller
+than this score."
+ :group 'gnus-score-default
+ :type 'integer)
+
(defcustom gnus-summary-zcore-fuzz 0
"*Fuzziness factor for the zcore in the summary buffer.
Articles with scores closer than this to `gnus-summary-default-score'
:type 'boolean)
(defcustom gnus-auto-select-first t
- "*If nil, don't select the first unread article when entering a group.
-If this variable is `best', select the highest-scored unread article
-in the group. If t, select the first unread article.
-
-This variable can also be a function to place point on a likely
-subject line. Useful values include `gnus-summary-first-unread-subject',
-`gnus-summary-first-unread-article' and
-`gnus-summary-best-unread-article'.
-
-If you want to prevent automatic selection of the first unread article
-in some newsgroups, set the variable to nil in
-`gnus-select-group-hook'."
+ "*If non-nil, select the article under point.
+Which article this is is controlled by the `gnus-auto-select-subject'
+variable.
+
+If you want to prevent automatic selection of articles in some
+newsgroups, set the variable to nil in `gnus-select-group-hook'."
:group 'gnus-group-select
:type '(choice (const :tag "none" nil)
- (const best)
- (sexp :menu-tag "first" t)
- (function-item gnus-summary-first-unread-subject)
- (function-item gnus-summary-first-unread-article)
- (function-item gnus-summary-best-unread-article)))
+ (sexp :menu-tag "first" t)))
+
+(defcustom gnus-auto-select-subject 'unread
+ "*Says what subject to place under point when entering a group.
+
+This variable can either be the symbols `first' (place point on the
+first subject), `unread' (place point on the subject line of the first
+unread article), `best' (place point on the subject line of the
+higest-scored article), `unseen' (place point on the subject line of
+the first unseen article), or a function to be called to place point on
+some subject line.."
+ :group 'gnus-group-select
+ :type '(choice (const best)
+ (const unread)
+ (const first)
+ (const unseen)))
(defcustom gnus-auto-select-next t
"*If non-nil, offer to go to the next group from the end of the previous.
(cons :value ("" "") regexp (repeat string))
(sexp :value nil))))
-(defcustom gnus-unread-mark ? ;Whitespace
+(defcustom gnus-unread-mark ? ;Whitespace
"*Mark used for unread articles."
:group 'gnus-summary-marks
:type 'character)
:group 'gnus-summary-marks
:type 'character)
-(defcustom gnus-forwarded-mark ?O
+(defcustom gnus-forwarded-mark ?F
"*Mark used for articles that have been forwarded."
:group 'gnus-summary-marks
:type 'character)
+(defcustom gnus-recent-mark ?N
+ "*Mark used for articles that are recent."
+ :group 'gnus-summary-marks
+ :type 'character)
+
(defcustom gnus-cached-mark ?*
"*Mark used for articles that are in the cache."
:group 'gnus-summary-marks
:type 'character)
(defcustom gnus-saved-mark ?S
- "*Mark used for articles that have been saved to."
+ "*Mark used for articles that have been saved."
+ :group 'gnus-summary-marks
+ :type 'character)
+
+(defcustom gnus-unseen-mark ?.
+ "*Mark used for articles that haven't been seen."
:group 'gnus-summary-marks
:type 'character)
-(defcustom gnus-no-mark ? ;Whitespace
+(defcustom gnus-no-mark ? ;Whitespace
"*Mark used for articles that have no other secondary mark."
:group 'gnus-summary-marks
:type 'character)
:group 'gnus-summary-marks
:type 'character)
-(defcustom gnus-empty-thread-mark ? ;Whitespace
+(defcustom gnus-empty-thread-mark ? ;Whitespace
"*There is no thread under the article."
:group 'gnus-summary-marks
:type 'character)
(defcustom gnus-summary-mode-hook nil
"*A hook for Gnus summary mode.
This hook is run before any variables are set in the summary buffer."
- :options '(turn-on-gnus-mailing-list-mode)
+ :options '(turn-on-gnus-mailing-list-mode gnus-pick-mode)
:group 'gnus-summary-various
:type 'hook)
:group 'gnus-summary
:type 'hook)
+(defcustom gnus-summary-display-arrow
+ (and (fboundp 'display-graphic-p)
+ (display-graphic-p))
+ "*If non-nil, display an arrow highlighting the current article."
+ :version "21.1"
+ :group 'gnus-summary
+ :type 'boolean)
+
(defcustom gnus-summary-selected-face 'gnus-summary-selected-face
"Face used for highlighting the current article in the summary buffer."
:group 'gnus-summary-visual
(defcustom gnus-summary-highlight
'(((= mark gnus-canceled-mark)
. gnus-summary-cancelled-face)
- ((and (> score default)
+ ((and (> score default-high)
(or (= mark gnus-dormant-mark)
(= mark gnus-ticked-mark)))
. gnus-summary-high-ticked-face)
- ((and (< score default)
+ ((and (< score default-low)
(or (= mark gnus-dormant-mark)
(= mark gnus-ticked-mark)))
. gnus-summary-low-ticked-face)
((or (= mark gnus-dormant-mark)
(= mark gnus-ticked-mark))
. gnus-summary-normal-ticked-face)
- ((and (> score default) (= mark gnus-ancient-mark))
+ ((and (> score default-high) (= mark gnus-ancient-mark))
. gnus-summary-high-ancient-face)
- ((and (< score default) (= mark gnus-ancient-mark))
+ ((and (< score default-low) (= mark gnus-ancient-mark))
. gnus-summary-low-ancient-face)
((= mark gnus-ancient-mark)
. gnus-summary-normal-ancient-face)
- ((and (> score default) (= mark gnus-unread-mark))
+ ((and (> score default-high) (= mark gnus-unread-mark))
. gnus-summary-high-unread-face)
- ((and (< score default) (= mark gnus-unread-mark))
+ ((and (< score default-low) (= mark gnus-unread-mark))
. gnus-summary-low-unread-face)
((= mark gnus-unread-mark)
. gnus-summary-normal-unread-face)
- ((and (> score default) (memq mark (list gnus-downloadable-mark
- gnus-undownloaded-mark)))
+ ((and (> score default-high) (memq mark (list gnus-downloadable-mark
+ gnus-undownloaded-mark)))
. gnus-summary-high-unread-face)
- ((and (< score default) (memq mark (list gnus-downloadable-mark
- gnus-undownloaded-mark)))
+ ((and (< score default-low) (memq mark (list gnus-downloadable-mark
+ gnus-undownloaded-mark)))
. gnus-summary-low-unread-face)
((and (memq mark (list gnus-downloadable-mark gnus-undownloaded-mark))
(memq article gnus-newsgroup-unreads))
. gnus-summary-normal-unread-face)
((memq mark (list gnus-downloadable-mark gnus-undownloaded-mark))
. gnus-summary-normal-read-face)
- ((> score default)
+ ((> score default-high)
. gnus-summary-high-read-face)
- ((< score default)
+ ((< score default-low)
. gnus-summary-low-read-face)
(t
. gnus-summary-normal-read-face))
You can use the following variables in the FORM field.
-score: The articles score
-default: The default article score.
-below: The score below which articles are automatically marked as read.
-mark: The articles mark."
+score: The article's score
+default: The default article score.
+default-high: The default score for high scored articles.
+default-low: The default score for low scored articles.
+below: The score below which articles are automatically marked as read.
+mark: The articles mark."
:group 'gnus-summary-visual
:type '(repeat (cons (sexp :tag "Form" nil)
face)))
:function-document
"Return the ignored charsets of GROUP."
:variable gnus-group-ignored-charsets-alist
- :variable-default
+ :variable-default
'(("alt\\.chinese\\.text" iso-8859-1))
:variable-document
"Alist of regexps (to match group names) and charsets that should be ignored.
:variable-group gnus-charset
:variable-type '(repeat (cons (regexp :tag "Group")
(repeat symbol)))
- :parameter-type '(choice :tag "Ignored charsets"
+ :parameter-type '(choice :tag "Ignored charsets"
:value nil
(repeat (symbol)))
:parameter-document "\
:group 'gnus-summary
:type '(choice boolean regexp))
+(defcustom gnus-summary-muttprint-program "muttprint"
+ "Command (and optional arguments) used to run Muttprint."
+ :group 'gnus-summary
+ :type 'string)
+
;;; Internal variables
+(defvar gnus-summary-display-cache nil)
(defvar gnus-article-mime-handles nil)
(defvar gnus-article-decoded-p nil)
(defvar gnus-article-charset nil)
(defvar gnus-current-move-group nil)
(defvar gnus-current-copy-group nil)
(defvar gnus-current-crosspost-group nil)
+(defvar gnus-newsgroup-display nil)
(defvar gnus-newsgroup-dependencies nil)
(defvar gnus-newsgroup-adaptive nil)
(?l (bbb-grouplens-score gnus-tmp-header) ?s)
(?V (gnus-thread-total-score (and (boundp 'thread) (car thread))) ?d)
(?U gnus-tmp-unread ?c)
- (?f (gnus-summary-from-or-to-or-newsgroups gnus-tmp-header) ?s)
+ (?f (gnus-summary-from-or-to-or-newsgroups gnus-tmp-header gnus-tmp-from)
+ ?s)
(?t (gnus-summary-number-of-articles-in-thread
(and (boundp 'thread) (car thread)) gnus-tmp-level)
?d)
(and (boundp 'thread) (car thread)) gnus-tmp-level t)
?c)
(?u gnus-tmp-user-defined ?s)
- (?P (gnus-pick-line-number) ?d))
+ (?P (gnus-pick-line-number) ?d)
+ (?B gnus-tmp-thread-tree-header-string ?s)
+ (user-date (gnus-user-date
+ ,(macroexpand '(mail-header-date gnus-tmp-header))) ?s))
"An alist of format specifications that can appear in summary lines.
These are paired with what variables they correspond with, along with
the type of the variable (string, integer, character, etc).")
(defvar gnus-newsgroup-forwarded nil
"List of articles that have been forwarded in the current newsgroup.")
+(defvar gnus-newsgroup-recent nil
+ "List of articles that have are recent in the current newsgroup.")
+
(defvar gnus-newsgroup-expirable nil
"List of articles in the current newsgroup that can be expired.")
(defvar gnus-newsgroup-dormant nil
"List of dormant articles in the current newsgroup.")
+(defvar gnus-newsgroup-unseen nil
+ "List of unseen articles in the current newsgroup.")
+
+(defvar gnus-newsgroup-seen nil
+ "Range of seen articles in the current newsgroup.")
+
+(defvar gnus-newsgroup-articles nil
+ "List of articles in the current newsgroup.")
+
(defvar gnus-newsgroup-scored nil
"List of scored articles in the current newsgroup.")
gnus-newsgroup-unselected gnus-newsgroup-marked
gnus-newsgroup-reads gnus-newsgroup-saved
gnus-newsgroup-replied gnus-newsgroup-forwarded
+ gnus-newsgroup-recent
gnus-newsgroup-expirable
gnus-newsgroup-processable gnus-newsgroup-killed
gnus-newsgroup-downloadable gnus-newsgroup-undownloaded
- gnus-newsgroup-unsendable
+ gnus-newsgroup-unsendable gnus-newsgroup-unseen
+ gnus-newsgroup-seen gnus-newsgroup-articles
gnus-newsgroup-bookmarks gnus-newsgroup-dormant
gnus-newsgroup-headers gnus-newsgroup-threads
gnus-newsgroup-prepared gnus-summary-highlight-line-function
gnus-cache-removable-articles gnus-newsgroup-cached
gnus-newsgroup-data gnus-newsgroup-data-reverse
gnus-newsgroup-limit gnus-newsgroup-limits
- gnus-newsgroup-charset)
+ gnus-newsgroup-charset gnus-newsgroup-display)
"Variables that are buffer-local to the summary buffers.")
(defvar gnus-newsgroup-variables nil
- "Variables that have separate values in the newsgroups.")
+ "A list of variables that have separate values in different newsgroups.
+A list of newsgroup (summary buffer) local variables, or cons of
+variables and their default values (when the default values are not
+nil), that should be made global while the summary buffer is active.
+These variables can be used to set variables in the group parameters
+while still allowing them to affect operations done in other
+buffers. For example:
+
+\(setq gnus-newsgroup-variables
+ '(message-use-followup-to
+ (gnus-visible-headers .
+ \"^From:\\\\|^Newsgroups:\\\\|^Subject:\\\\|^Date:\\\\|^To:\")))
+")
;; Byte-compiler warning.
(eval-when-compile (defvar gnus-article-mode-map))
'(mail-decode-encoded-word-string)
"List of methods used to decode encoded words.
-This variable is a list of FUNCTION or (REGEXP . FUNCTION). If item is
-FUNCTION, FUNCTION will be apply to all newsgroups. If item is a
-(REGEXP . FUNCTION), FUNCTION will be only apply to thes newsgroups
+This variable is a list of FUNCTION or (REGEXP . FUNCTION). If item
+is FUNCTION, FUNCTION will be apply to all newsgroups. If item is a
+\(REGEXP . FUNCTION), FUNCTION will be only apply to thes newsgroups
whose names match REGEXP.
For example:
-((\"chinese\" . gnus-decode-encoded-word-string-by-guess)
+\((\"chinese\" . gnus-decode-encoded-word-string-by-guess)
mail-decode-encoded-word-string
(\"chinese\" . rfc1843-decode-string))")
(string-match (car x) gnus-newsgroup-name))
(nconc gnus-decode-encoded-word-methods-cache
(list (cdr x))))))
- gnus-decode-encoded-word-methods))
+ gnus-decode-encoded-word-methods))
(let ((xlist gnus-decode-encoded-word-methods-cache))
(pop xlist)
(while xlist
;; Multiple spaces.
(while (string-match "[ \t][ \t]+" mystr)
(setq mystr (concat (substring mystr 0 (match-beginning 0))
- " "
- (substring mystr (match-end 0)))))
+ " "
+ (substring mystr (match-end 0)))))
;; Leading spaces.
(when (string-match "^[ \t]+" mystr)
(setq mystr (substring mystr (match-end 0))))
gnus-mouse-2 gnus-mouse-pick-article
"m" gnus-summary-mail-other-window
"a" gnus-summary-post-news
+ "i" gnus-summary-news-other-window
"x" gnus-summary-limit-to-unread
"s" gnus-summary-isearch-article
"t" gnus-summary-toggle-header
"S" gnus-summary-limit-include-expunged
"C" gnus-summary-catchup
"H" gnus-summary-catchup-to-here
+ "h" gnus-summary-catchup-from-here
"\C-c" gnus-summary-catchup-all
"k" gnus-summary-kill-same-subject-and-select
"K" gnus-summary-kill-same-subject
"d" gnus-summary-limit-exclude-dormant
"t" gnus-summary-limit-to-age
"x" gnus-summary-limit-to-extra
+ "p" gnus-summary-limit-to-display-predicate
"E" gnus-summary-limit-include-expunged
"c" gnus-summary-limit-exclude-childless-dormant
"C" gnus-summary-limit-mark-excluded-as-read
"l" gnus-summary-stop-page-breaking
"r" gnus-summary-caesar-message
"t" gnus-summary-toggle-header
+ "g" gnus-summary-toggle-smiley
+ "u" gnus-article-treat-unfold-headers
+ "n" gnus-article-treat-fold-newsgroups
"v" gnus-summary-verbose-headers
"a" gnus-article-strip-headers-in-body ;; mnemonic: wash archive
"p" gnus-article-verify-x-pgp-sig
"c" gnus-article-highlight-citation
"s" gnus-article-highlight-signature)
+ (gnus-define-keys (gnus-summary-wash-display-map "D" gnus-summary-wash-map)
+ "x" gnus-article-display-x-face
+ "s" gnus-summary-toggle-smiley
+ "f" gnus-treat-from-picon
+ "m" gnus-treat-mail-picon
+ "n" gnus-treat-newsgroups-picon)
+
(gnus-define-keys (gnus-summary-wash-mime-map "M" gnus-summary-wash-map)
"w" gnus-article-decode-mime-words
"c" gnus-article-decode-charset
"h" gnus-summary-save-article-folder
"v" gnus-summary-save-article-vm
"p" gnus-summary-pipe-output
+ "P" gnus-summary-muttprint
"s" gnus-soup-add-article)
(gnus-define-keys (gnus-summary-mime-map "K" gnus-summary-mode-map)
(unless (boundp 'gnus-summary-misc-menu)
(easy-menu-define
- gnus-summary-kill-menu gnus-summary-mode-map ""
- (cons
- "Score"
- (nconc
- (list
- ["Customize" gnus-score-customize t])
- (gnus-make-score-map 'increase)
- (gnus-make-score-map 'lower)
- '(("Mark"
- ["Kill below" gnus-summary-kill-below t]
- ["Mark above" gnus-summary-mark-above t]
- ["Tick above" gnus-summary-tick-above t]
- ["Clear above" gnus-summary-clear-above t])
- ["Current score" gnus-summary-current-score t]
- ["Set score" gnus-summary-set-score t]
- ["Switch current score file..." gnus-score-change-score-file t]
- ["Set mark below..." gnus-score-set-mark-below t]
- ["Set expunge below..." gnus-score-set-expunge-below t]
- ["Edit current score file" gnus-score-edit-current-scores t]
- ["Edit score file" gnus-score-edit-file t]
- ["Trace score" gnus-score-find-trace t]
- ["Find words" gnus-score-find-favourite-words t]
- ["Rescore buffer" gnus-summary-rescore t]
- ["Increase score..." gnus-summary-increase-score t]
- ["Lower score..." gnus-summary-lower-score t]))))
-
- ;; Define both the Article menu in the summary buffer and the equivalent
- ;; Commands menu in the article buffer here for consistency.
+ gnus-summary-kill-menu gnus-summary-mode-map ""
+ (cons
+ "Score"
+ (nconc
+ (list
+ ["Customize" gnus-score-customize t])
+ (gnus-make-score-map 'increase)
+ (gnus-make-score-map 'lower)
+ '(("Mark"
+ ["Kill below" gnus-summary-kill-below t]
+ ["Mark above" gnus-summary-mark-above t]
+ ["Tick above" gnus-summary-tick-above t]
+ ["Clear above" gnus-summary-clear-above t])
+ ["Current score" gnus-summary-current-score t]
+ ["Set score" gnus-summary-set-score t]
+ ["Switch current score file..." gnus-score-change-score-file t]
+ ["Set mark below..." gnus-score-set-mark-below t]
+ ["Set expunge below..." gnus-score-set-expunge-below t]
+ ["Edit current score file" gnus-score-edit-current-scores t]
+ ["Edit score file" gnus-score-edit-file t]
+ ["Trace score" gnus-score-find-trace t]
+ ["Find words" gnus-score-find-favourite-words t]
+ ["Rescore buffer" gnus-summary-rescore t]
+ ["Increase score..." gnus-summary-increase-score t]
+ ["Lower score..." gnus-summary-lower-score t]))))
+
+ ;; Define both the Article menu in the summary buffer and the
+ ;; equivalent Commands menu in the article buffer here for
+ ;; consistency.
(let ((innards
- `(("Hide"
- ["All" gnus-article-hide t]
- ["Headers" gnus-article-hide-headers t]
- ["Signature" gnus-article-hide-signature t]
- ["Citation" gnus-article-hide-citation t]
+ `(("Hide"
+ ["All" gnus-article-hide t]
+ ["Headers" gnus-article-hide-headers t]
+ ["Signature" gnus-article-hide-signature t]
+ ["Citation" gnus-article-hide-citation t]
["List identifiers" gnus-article-hide-list-identifiers t]
- ["PGP" gnus-article-hide-pgp t]
+ ["PGP" gnus-article-hide-pgp t]
["Banner" gnus-article-strip-banner t]
- ["Boring headers" gnus-article-hide-boring-headers t])
- ("Highlight"
- ["All" gnus-article-highlight t]
- ["Headers" gnus-article-highlight-headers t]
- ["Signature" gnus-article-highlight-signature t]
- ["Citation" gnus-article-highlight-citation t])
+ ["Boring headers" gnus-article-hide-boring-headers t])
+ ("Highlight"
+ ["All" gnus-article-highlight t]
+ ["Headers" gnus-article-highlight-headers t]
+ ["Signature" gnus-article-highlight-signature t]
+ ["Citation" gnus-article-highlight-citation t])
("MIME"
["Words" gnus-article-decode-mime-words t]
["Charset" gnus-article-decode-charset t]
["View all" gnus-mime-view-all-parts t]
["Verify and Decrypt" gnus-summary-force-verify-and-decrypt t]
["Encrypt body" gnus-article-encrypt-body t])
- ("Date"
- ["Local" gnus-article-date-local t]
- ["ISO8601" gnus-article-date-iso8601 t]
- ["UT" gnus-article-date-ut t]
- ["Original" gnus-article-date-original t]
- ["Lapsed" gnus-article-date-lapsed t]
- ["User-defined" gnus-article-date-user t])
- ("Washing"
- ("Remove Blanks"
- ["Leading" gnus-article-strip-leading-blank-lines t]
- ["Multiple" gnus-article-strip-multiple-blank-lines t]
- ["Trailing" gnus-article-remove-trailing-blank-lines t]
- ["All of the above" gnus-article-strip-blank-lines t]
- ["All" gnus-article-strip-all-blank-lines t]
- ["Leading space" gnus-article-strip-leading-space t]
+ ("Date"
+ ["Local" gnus-article-date-local t]
+ ["ISO8601" gnus-article-date-iso8601 t]
+ ["UT" gnus-article-date-ut t]
+ ["Original" gnus-article-date-original t]
+ ["Lapsed" gnus-article-date-lapsed t]
+ ["User-defined" gnus-article-date-user t])
+ ("Display"
+ ["Toggle smiley" gnus-summary-toggle-smiley t]
+ ["Show X-Face" gnus-article-display-x-face t]
+ ["Show picons in From" gnus-treat-from-picon t]
+ ["Show picons in mail headers" gnus-treat-mail-picon t]
+ ["Show picons in news headers" gnus-treat-newsgroups-picon t])
+ ("Washing"
+ ("Remove Blanks"
+ ["Leading" gnus-article-strip-leading-blank-lines t]
+ ["Multiple" gnus-article-strip-multiple-blank-lines t]
+ ["Trailing" gnus-article-remove-trailing-blank-lines t]
+ ["All of the above" gnus-article-strip-blank-lines t]
+ ["All" gnus-article-strip-all-blank-lines t]
+ ["Leading space" gnus-article-strip-leading-space t]
["Trailing space" gnus-article-strip-trailing-space t]
- ["Leading space in headers"
+ ["Leading space in headers"
gnus-article-remove-leading-whitespace t])
- ["Overstrike" gnus-article-treat-overstrike t]
- ["Dumb quotes" gnus-article-treat-dumbquotes t]
- ["Emphasis" gnus-article-emphasize t]
- ["Word wrap" gnus-article-fill-cited-article t]
+ ["Overstrike" gnus-article-treat-overstrike t]
+ ["Dumb quotes" gnus-article-treat-dumbquotes t]
+ ["Emphasis" gnus-article-emphasize t]
+ ["Word wrap" gnus-article-fill-cited-article t]
["Fill long lines" gnus-article-fill-long-lines t]
["Capitalize sentences" gnus-article-capitalize-sentences t]
- ["CR" gnus-article-remove-cr t]
- ["Show X-Face" gnus-article-display-x-face t]
- ["Quoted-Printable" gnus-article-de-quoted-unreadable t]
- ["Base64" gnus-article-de-base64-unreadable t]
- ["Rot 13" gnus-summary-caesar-message
+ ["CR" gnus-article-remove-cr t]
+ ["Quoted-Printable" gnus-article-de-quoted-unreadable t]
+ ["Base64" gnus-article-de-base64-unreadable t]
+ ["Rot 13" gnus-summary-caesar-message
,@(if (featurep 'xemacs) '(t)
'(:help "\"Caesar rotate\" article by 13"))]
- ["Unix pipe" gnus-summary-pipe-message t]
- ["Add buttons" gnus-article-add-buttons t]
- ["Add buttons to head" gnus-article-add-buttons-to-head t]
- ["Stop page breaking" gnus-summary-stop-page-breaking t]
- ["Verbose header" gnus-summary-verbose-headers t]
- ["Toggle header" gnus-summary-toggle-header t]
+ ["Unix pipe" gnus-summary-pipe-message t]
+ ["Add buttons" gnus-article-add-buttons t]
+ ["Add buttons to head" gnus-article-add-buttons-to-head t]
+ ["Stop page breaking" gnus-summary-stop-page-breaking t]
+ ["Verbose header" gnus-summary-verbose-headers t]
+ ["Toggle header" gnus-summary-toggle-header t]
+ ["Unfold headers" gnus-article-treat-unfold-headers t]
+ ["Fold newsgroups" gnus-article-treat-fold-newsgroups t]
["Html" gnus-article-wash-html t]
["Verify X-PGP-Sig" gnus-article-verify-x-pgp-sig t]
["HZ" gnus-article-decode-HZ t])
- ("Output"
- ["Save in default format" gnus-summary-save-article
+ ("Output"
+ ["Save in default format" gnus-summary-save-article
,@(if (featurep 'xemacs) '(t)
'(:help "Save article using default method"))]
- ["Save in file" gnus-summary-save-article-file
+ ["Save in file" gnus-summary-save-article-file
,@(if (featurep 'xemacs) '(t)
'(:help "Save article in file"))]
- ["Save in Unix mail format" gnus-summary-save-article-mail t]
- ["Save in MH folder" gnus-summary-save-article-folder t]
- ["Save in VM folder" gnus-summary-save-article-vm t]
- ["Save in RMAIL mbox" gnus-summary-save-article-rmail t]
- ["Save body in file" gnus-summary-save-article-body-file t]
- ["Pipe through a filter" gnus-summary-pipe-output t]
- ["Add to SOUP packet" gnus-soup-add-article t]
- ["Print" gnus-summary-print-article t])
- ("Backend"
- ["Respool article..." gnus-summary-respool-article t]
- ["Move article..." gnus-summary-move-article
- (gnus-check-backend-function
- 'request-move-article gnus-newsgroup-name)]
- ["Copy article..." gnus-summary-copy-article t]
- ["Crosspost article..." gnus-summary-crosspost-article
- (gnus-check-backend-function
- 'request-replace-article gnus-newsgroup-name)]
- ["Import file..." gnus-summary-import-article t]
- ["Create article..." gnus-summary-create-article t]
- ["Check if posted" gnus-summary-article-posted-p t]
- ["Edit article" gnus-summary-edit-article
- (not (gnus-group-read-only-p))]
- ["Delete article" gnus-summary-delete-article
- (gnus-check-backend-function
- 'request-expire-articles gnus-newsgroup-name)]
- ["Query respool" gnus-summary-respool-query t]
+ ["Save in Unix mail format" gnus-summary-save-article-mail t]
+ ["Save in MH folder" gnus-summary-save-article-folder t]
+ ["Save in VM folder" gnus-summary-save-article-vm t]
+ ["Save in RMAIL mbox" gnus-summary-save-article-rmail t]
+ ["Save body in file" gnus-summary-save-article-body-file t]
+ ["Pipe through a filter" gnus-summary-pipe-output t]
+ ["Add to SOUP packet" gnus-soup-add-article t]
+ ["Print with Muttprint" gnus-summary-muttprint t]
+ ["Print" gnus-summary-print-article t])
+ ("Backend"
+ ["Respool article..." gnus-summary-respool-article t]
+ ["Move article..." gnus-summary-move-article
+ (gnus-check-backend-function
+ 'request-move-article gnus-newsgroup-name)]
+ ["Copy article..." gnus-summary-copy-article t]
+ ["Crosspost article..." gnus-summary-crosspost-article
+ (gnus-check-backend-function
+ 'request-replace-article gnus-newsgroup-name)]
+ ["Import file..." gnus-summary-import-article t]
+ ["Create article..." gnus-summary-create-article t]
+ ["Check if posted" gnus-summary-article-posted-p t]
+ ["Edit article" gnus-summary-edit-article
+ (not (gnus-group-read-only-p))]
+ ["Delete article" gnus-summary-delete-article
+ (gnus-check-backend-function
+ 'request-expire-articles gnus-newsgroup-name)]
+ ["Query respool" gnus-summary-respool-query t]
["Trace respool" gnus-summary-respool-trace t]
- ["Delete expirable articles" gnus-summary-expire-articles-now
- (gnus-check-backend-function
- 'request-expire-articles gnus-newsgroup-name)])
- ("Extract"
- ["Uudecode" gnus-uu-decode-uu
+ ["Delete expirable articles" gnus-summary-expire-articles-now
+ (gnus-check-backend-function
+ 'request-expire-articles gnus-newsgroup-name)])
+ ("Extract"
+ ["Uudecode" gnus-uu-decode-uu
,@(if (featurep 'xemacs) '(t)
'(:help "Decode uuencoded article(s)"))]
- ["Uudecode and save" gnus-uu-decode-uu-and-save t]
- ["Unshar" gnus-uu-decode-unshar t]
- ["Unshar and save" gnus-uu-decode-unshar-and-save t]
- ["Save" gnus-uu-decode-save t]
- ["Binhex" gnus-uu-decode-binhex t]
- ["Postscript" gnus-uu-decode-postscript t])
- ("Cache"
- ["Enter article" gnus-cache-enter-article t]
- ["Remove article" gnus-cache-remove-article t])
+ ["Uudecode and save" gnus-uu-decode-uu-and-save t]
+ ["Unshar" gnus-uu-decode-unshar t]
+ ["Unshar and save" gnus-uu-decode-unshar-and-save t]
+ ["Save" gnus-uu-decode-save t]
+ ["Binhex" gnus-uu-decode-binhex t]
+ ["Postscript" gnus-uu-decode-postscript t])
+ ("Cache"
+ ["Enter article" gnus-cache-enter-article t]
+ ["Remove article" gnus-cache-remove-article t])
["Translate" gnus-article-babel t]
- ["Select article buffer" gnus-summary-select-article-buffer t]
- ["Enter digest buffer" gnus-summary-enter-digest-group t]
- ["Isearch article..." gnus-summary-isearch-article t]
- ["Beginning of the article" gnus-summary-beginning-of-article t]
- ["End of the article" gnus-summary-end-of-article t]
- ["Fetch parent of article" gnus-summary-refer-parent-article t]
- ["Fetch referenced articles" gnus-summary-refer-references t]
- ["Fetch current thread" gnus-summary-refer-thread t]
- ["Fetch article with id..." gnus-summary-refer-article t]
- ["Setup Mailing List Params" gnus-mailing-list-insinuate t]
- ["Redisplay" gnus-summary-show-article t])))
+ ["Select article buffer" gnus-summary-select-article-buffer t]
+ ["Enter digest buffer" gnus-summary-enter-digest-group t]
+ ["Isearch article..." gnus-summary-isearch-article t]
+ ["Beginning of the article" gnus-summary-beginning-of-article t]
+ ["End of the article" gnus-summary-end-of-article t]
+ ["Fetch parent of article" gnus-summary-refer-parent-article t]
+ ["Fetch referenced articles" gnus-summary-refer-references t]
+ ["Fetch current thread" gnus-summary-refer-thread t]
+ ["Fetch article with id..." gnus-summary-refer-article t]
+ ["Setup Mailing List Params" gnus-mailing-list-insinuate t]
+ ["Redisplay" gnus-summary-show-article t]
+ ["Raw article" gnus-summary-show-raw-article t])))
(easy-menu-define
- gnus-summary-article-menu gnus-summary-mode-map ""
- (cons "Article" innards))
+ gnus-summary-article-menu gnus-summary-mode-map ""
+ (cons "Article" innards))
(if (not (keymapp gnus-summary-article-menu))
(easy-menu-define
gnus-article-commands-menu gnus-article-mode-map ""
(cons "Commands" innards))
;; in Emacs, don't share menu.
- (setq gnus-article-commands-menu
+ (setq gnus-article-commands-menu
(copy-keymap gnus-summary-article-menu))
(define-key gnus-article-mode-map [menu-bar commands]
(cons "Commands" gnus-article-commands-menu))))
(easy-menu-define
- gnus-summary-thread-menu gnus-summary-mode-map ""
- '("Threads"
- ["Toggle threading" gnus-summary-toggle-threads t]
- ["Hide threads" gnus-summary-hide-all-threads t]
- ["Show threads" gnus-summary-show-all-threads t]
- ["Hide thread" gnus-summary-hide-thread t]
- ["Show thread" gnus-summary-show-thread t]
- ["Go to next thread" gnus-summary-next-thread t]
- ["Go to previous thread" gnus-summary-prev-thread t]
- ["Go down thread" gnus-summary-down-thread t]
- ["Go up thread" gnus-summary-up-thread t]
- ["Top of thread" gnus-summary-top-thread t]
- ["Mark thread as read" gnus-summary-kill-thread t]
- ["Lower thread score" gnus-summary-lower-thread t]
- ["Raise thread score" gnus-summary-raise-thread t]
- ["Rethread current" gnus-summary-rethread-current t]))
+ gnus-summary-thread-menu gnus-summary-mode-map ""
+ '("Threads"
+ ["Toggle threading" gnus-summary-toggle-threads t]
+ ["Hide threads" gnus-summary-hide-all-threads t]
+ ["Show threads" gnus-summary-show-all-threads t]
+ ["Hide thread" gnus-summary-hide-thread t]
+ ["Show thread" gnus-summary-show-thread t]
+ ["Go to next thread" gnus-summary-next-thread t]
+ ["Go to previous thread" gnus-summary-prev-thread t]
+ ["Go down thread" gnus-summary-down-thread t]
+ ["Go up thread" gnus-summary-up-thread t]
+ ["Top of thread" gnus-summary-top-thread t]
+ ["Mark thread as read" gnus-summary-kill-thread t]
+ ["Lower thread score" gnus-summary-lower-thread t]
+ ["Raise thread score" gnus-summary-raise-thread t]
+ ["Rethread current" gnus-summary-rethread-current t]))
(easy-menu-define
- gnus-summary-post-menu gnus-summary-mode-map ""
- `("Post"
- ["Post an article" gnus-summary-post-news
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Post an article"))]
- ["Followup" gnus-summary-followup
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Post followup to this article"))]
- ["Followup and yank" gnus-summary-followup-with-original
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Post followup to this article, quoting its contents"))]
- ["Supersede article" gnus-summary-supersede-article t]
- ["Cancel article" gnus-summary-cancel-article
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Cancel an article you posted"))]
- ["Reply" gnus-summary-reply t]
- ["Reply and yank" gnus-summary-reply-with-original t]
- ["Wide reply" gnus-summary-wide-reply t]
- ["Wide reply and yank" gnus-summary-wide-reply-with-original
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Mail a reply, quoting this article"))]
- ["Mail forward" gnus-summary-mail-forward t]
- ["Post forward" gnus-summary-post-forward t]
- ["Digest and mail" gnus-uu-digest-mail-forward t]
- ["Digest and post" gnus-uu-digest-post-forward t]
- ["Resend message" gnus-summary-resend-message t]
- ["Send bounced mail" gnus-summary-resend-bounced-mail t]
- ["Send a mail" gnus-summary-mail-other-window t]
- ["Uuencode and post" gnus-uu-post-news
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Post a uuencoded article"))]
- ["Followup via news" gnus-summary-followup-to-mail t]
- ["Followup via news and yank"
- gnus-summary-followup-to-mail-with-original t]
- ;;("Draft"
- ;;["Send" gnus-summary-send-draft t]
- ;;["Send bounced" gnus-resend-bounced-mail t])
- ))
-
- (cond
+ gnus-summary-post-menu gnus-summary-mode-map ""
+ `("Post"
+ ["Send a message (mail or news)" gnus-summary-post-news
+ ,@(if (featurep 'xemacs) '(t)
+ '(:help "Post an article"))]
+ ["Followup" gnus-summary-followup
+ ,@(if (featurep 'xemacs) '(t)
+ '(:help "Post followup to this article"))]
+ ["Followup and yank" gnus-summary-followup-with-original
+ ,@(if (featurep 'xemacs) '(t)
+ '(:help "Post followup to this article, quoting its contents"))]
+ ["Supersede article" gnus-summary-supersede-article t]
+ ["Cancel article" gnus-summary-cancel-article
+ ,@(if (featurep 'xemacs) '(t)
+ '(:help "Cancel an article you posted"))]
+ ["Reply" gnus-summary-reply t]
+ ["Reply and yank" gnus-summary-reply-with-original t]
+ ["Wide reply" gnus-summary-wide-reply t]
+ ["Wide reply and yank" gnus-summary-wide-reply-with-original
+ ,@(if (featurep 'xemacs) '(t)
+ '(:help "Mail a reply, quoting this article"))]
+ ["Mail forward" gnus-summary-mail-forward t]
+ ["Post forward" gnus-summary-post-forward t]
+ ["Digest and mail" gnus-uu-digest-mail-forward t]
+ ["Digest and post" gnus-uu-digest-post-forward t]
+ ["Resend message" gnus-summary-resend-message t]
+ ["Send bounced mail" gnus-summary-resend-bounced-mail t]
+ ["Send a mail" gnus-summary-mail-other-window t]
+ ["Create a local message" gnus-summary-news-other-window t]
+ ["Uuencode and post" gnus-uu-post-news
+ ,@(if (featurep 'xemacs) '(t)
+ '(:help "Post a uuencoded article"))]
+ ["Followup via news" gnus-summary-followup-to-mail t]
+ ["Followup via news and yank"
+ gnus-summary-followup-to-mail-with-original t]
+ ;;("Draft"
+ ;;["Send" gnus-summary-send-draft t]
+ ;;["Send bounced" gnus-resend-bounced-mail t])
+ ))
+
+ (cond
((not (keymapp gnus-summary-post-menu))
(setq gnus-article-post-menu gnus-summary-post-menu))
((not gnus-article-post-menu)
(cons "Post" gnus-article-post-menu))
(easy-menu-define
- gnus-summary-misc-menu gnus-summary-mode-map ""
- `("Misc"
- ("Mark Read"
- ["Mark as read" gnus-summary-mark-as-read-forward t]
- ["Mark same subject and select"
- gnus-summary-kill-same-subject-and-select t]
- ["Mark same subject" gnus-summary-kill-same-subject t]
- ["Catchup" gnus-summary-catchup
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Mark unread articles in this group as read"))]
- ["Catchup all" gnus-summary-catchup-all t]
- ["Catchup to here" gnus-summary-catchup-to-here t]
- ["Catchup region" gnus-summary-mark-region-as-read t]
- ["Mark excluded" gnus-summary-limit-mark-excluded-as-read t])
- ("Mark Various"
- ["Tick" gnus-summary-tick-article-forward t]
- ["Mark as dormant" gnus-summary-mark-as-dormant t]
- ["Remove marks" gnus-summary-clear-mark-forward t]
- ["Set expirable mark" gnus-summary-mark-as-expirable t]
- ["Set bookmark" gnus-summary-set-bookmark t]
- ["Remove bookmark" gnus-summary-remove-bookmark t])
- ("Mark Limit"
- ["Marks..." gnus-summary-limit-to-marks t]
- ["Subject..." gnus-summary-limit-to-subject t]
- ["Author..." gnus-summary-limit-to-author t]
- ["Age..." gnus-summary-limit-to-age t]
- ["Extra..." gnus-summary-limit-to-extra t]
- ["Score" gnus-summary-limit-to-score t]
- ["Unread" gnus-summary-limit-to-unread t]
- ["Non-dormant" gnus-summary-limit-exclude-dormant t]
- ["Articles" gnus-summary-limit-to-articles t]
- ["Pop limit" gnus-summary-pop-limit t]
- ["Show dormant" gnus-summary-limit-include-dormant t]
- ["Hide childless dormant"
- gnus-summary-limit-exclude-childless-dormant t]
- ;;["Hide thread" gnus-summary-limit-exclude-thread t]
- ["Hide marked" gnus-summary-limit-exclude-marks t]
- ["Show expunged" gnus-summary-limit-include-expunged t])
- ("Process Mark"
- ["Set mark" gnus-summary-mark-as-processable t]
- ["Remove mark" gnus-summary-unmark-as-processable t]
- ["Remove all marks" gnus-summary-unmark-all-processable t]
- ["Mark above" gnus-uu-mark-over t]
- ["Mark series" gnus-uu-mark-series t]
- ["Mark region" gnus-uu-mark-region t]
- ["Unmark region" gnus-uu-unmark-region t]
- ["Mark by regexp..." gnus-uu-mark-by-regexp t]
- ["Unmark by regexp..." gnus-uu-unmark-by-regexp t]
- ["Mark all" gnus-uu-mark-all t]
- ["Mark buffer" gnus-uu-mark-buffer t]
- ["Mark sparse" gnus-uu-mark-sparse t]
- ["Mark thread" gnus-uu-mark-thread t]
- ["Unmark thread" gnus-uu-unmark-thread t]
- ("Process Mark Sets"
- ["Kill" gnus-summary-kill-process-mark t]
- ["Yank" gnus-summary-yank-process-mark
- gnus-newsgroup-process-stack]
- ["Save" gnus-summary-save-process-mark t]))
- ("Scroll article"
- ["Page forward" gnus-summary-next-page
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Show next page of article"))]
- ["Page backward" gnus-summary-prev-page
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Show previous page of article"))]
- ["Line forward" gnus-summary-scroll-up t])
- ("Move"
- ["Next unread article" gnus-summary-next-unread-article t]
- ["Previous unread article" gnus-summary-prev-unread-article t]
- ["Next article" gnus-summary-next-article t]
- ["Previous article" gnus-summary-prev-article t]
- ["Next unread subject" gnus-summary-next-unread-subject t]
- ["Previous unread subject" gnus-summary-prev-unread-subject t]
- ["Next article same subject" gnus-summary-next-same-subject t]
- ["Previous article same subject" gnus-summary-prev-same-subject t]
- ["First unread article" gnus-summary-first-unread-article t]
- ["Best unread article" gnus-summary-best-unread-article t]
- ["Go to subject number..." gnus-summary-goto-subject t]
- ["Go to article number..." gnus-summary-goto-article t]
- ["Go to the last article" gnus-summary-goto-last-article t]
- ["Pop article off history" gnus-summary-pop-article t])
- ("Sort"
- ["Sort by number" gnus-summary-sort-by-number t]
- ["Sort by author" gnus-summary-sort-by-author t]
- ["Sort by subject" gnus-summary-sort-by-subject t]
- ["Sort by date" gnus-summary-sort-by-date t]
- ["Sort by score" gnus-summary-sort-by-score t]
- ["Sort by lines" gnus-summary-sort-by-lines t]
- ["Sort by characters" gnus-summary-sort-by-chars t]
- ["Original sort" gnus-summary-sort-by-original t])
- ("Help"
- ["Fetch group FAQ" gnus-summary-fetch-faq t]
- ["Describe group" gnus-summary-describe-group t]
- ["Read manual" gnus-info-find-node t])
- ("Modes"
- ["Pick and read" gnus-pick-mode t]
- ["Binary" gnus-binary-mode t])
- ("Regeneration"
- ["Regenerate" gnus-summary-prepare t]
- ["Insert cached articles" gnus-summary-insert-cached-articles t]
- ["Toggle threading" gnus-summary-toggle-threads t])
- ["See old articles" gnus-summary-insert-old-articles t]
- ["See new articles" gnus-summary-insert-new-articles t]
- ["Filter articles..." gnus-summary-execute-command t]
- ["Run command on subjects..." gnus-summary-universal-argument t]
- ["Search articles forward..." gnus-summary-search-article-forward t]
- ["Search articles backward..." gnus-summary-search-article-backward t]
- ["Toggle line truncation" gnus-summary-toggle-truncation t]
- ["Expand window" gnus-summary-expand-window t]
- ["Expire expirable articles" gnus-summary-expire-articles
- (gnus-check-backend-function
- 'request-expire-articles gnus-newsgroup-name)]
- ["Edit local kill file" gnus-summary-edit-local-kill t]
- ["Edit main kill file" gnus-summary-edit-global-kill t]
- ["Edit group parameters" gnus-summary-edit-parameters t]
- ["Customize group parameters" gnus-summary-customize-parameters t]
- ["Send a bug report" gnus-bug t]
- ("Exit"
- ["Catchup and exit" gnus-summary-catchup-and-exit
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Mark unread articles in this group as read, then exit"))]
- ["Catchup all and exit" gnus-summary-catchup-all-and-exit t]
- ["Catchup and goto next" gnus-summary-catchup-and-goto-next-group t]
- ["Exit group" gnus-summary-exit
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Exit current group, return to group selection mode"))]
- ["Exit group without updating" gnus-summary-exit-no-update t]
- ["Exit and goto next group" gnus-summary-next-group t]
- ["Exit and goto prev group" gnus-summary-prev-group t]
- ["Reselect group" gnus-summary-reselect-current-group t]
- ["Rescan group" gnus-summary-rescan-group t]
- ["Update dribble" gnus-summary-save-newsrc t])))
+ gnus-summary-misc-menu gnus-summary-mode-map ""
+ `("Gnus"
+ ("Mark Read"
+ ["Mark as read" gnus-summary-mark-as-read-forward t]
+ ["Mark same subject and select"
+ gnus-summary-kill-same-subject-and-select t]
+ ["Mark same subject" gnus-summary-kill-same-subject t]
+ ["Catchup" gnus-summary-catchup
+ ,@(if (featurep 'xemacs) '(t)
+ '(:help "Mark unread articles in this group as read"))]
+ ["Catchup all" gnus-summary-catchup-all t]
+ ["Catchup to here" gnus-summary-catchup-to-here t]
+ ["Catchup from here" gnus-summary-catchup-from-here t]
+ ["Catchup region" gnus-summary-mark-region-as-read t]
+ ["Mark excluded" gnus-summary-limit-mark-excluded-as-read t])
+ ("Mark Various"
+ ["Tick" gnus-summary-tick-article-forward t]
+ ["Mark as dormant" gnus-summary-mark-as-dormant t]
+ ["Remove marks" gnus-summary-clear-mark-forward t]
+ ["Set expirable mark" gnus-summary-mark-as-expirable t]
+ ["Set bookmark" gnus-summary-set-bookmark t]
+ ["Remove bookmark" gnus-summary-remove-bookmark t])
+ ("Limit to"
+ ["Marks..." gnus-summary-limit-to-marks t]
+ ["Subject..." gnus-summary-limit-to-subject t]
+ ["Author..." gnus-summary-limit-to-author t]
+ ["Age..." gnus-summary-limit-to-age t]
+ ["Extra..." gnus-summary-limit-to-extra t]
+ ["Score" gnus-summary-limit-to-score t]
+ ["Display Predicate" gnus-summary-limit-to-display-predicate t]
+ ["Unread" gnus-summary-limit-to-unread t]
+ ["Non-dormant" gnus-summary-limit-exclude-dormant t]
+ ["Articles" gnus-summary-limit-to-articles t]
+ ["Pop limit" gnus-summary-pop-limit t]
+ ["Show dormant" gnus-summary-limit-include-dormant t]
+ ["Hide childless dormant"
+ gnus-summary-limit-exclude-childless-dormant t]
+ ;;["Hide thread" gnus-summary-limit-exclude-thread t]
+ ["Hide marked" gnus-summary-limit-exclude-marks t]
+ ["Show expunged" gnus-summary-limit-include-expunged t])
+ ("Process Mark"
+ ["Set mark" gnus-summary-mark-as-processable t]
+ ["Remove mark" gnus-summary-unmark-as-processable t]
+ ["Remove all marks" gnus-summary-unmark-all-processable t]
+ ["Mark above" gnus-uu-mark-over t]
+ ["Mark series" gnus-uu-mark-series t]
+ ["Mark region" gnus-uu-mark-region t]
+ ["Unmark region" gnus-uu-unmark-region t]
+ ["Mark by regexp..." gnus-uu-mark-by-regexp t]
+ ["Unmark by regexp..." gnus-uu-unmark-by-regexp t]
+ ["Mark all" gnus-uu-mark-all t]
+ ["Mark buffer" gnus-uu-mark-buffer t]
+ ["Mark sparse" gnus-uu-mark-sparse t]
+ ["Mark thread" gnus-uu-mark-thread t]
+ ["Unmark thread" gnus-uu-unmark-thread t]
+ ("Process Mark Sets"
+ ["Kill" gnus-summary-kill-process-mark t]
+ ["Yank" gnus-summary-yank-process-mark
+ gnus-newsgroup-process-stack]
+ ["Save" gnus-summary-save-process-mark t]))
+ ("Scroll article"
+ ["Page forward" gnus-summary-next-page
+ ,@(if (featurep 'xemacs) '(t)
+ '(:help "Show next page of article"))]
+ ["Page backward" gnus-summary-prev-page
+ ,@(if (featurep 'xemacs) '(t)
+ '(:help "Show previous page of article"))]
+ ["Line forward" gnus-summary-scroll-up t])
+ ("Move"
+ ["Next unread article" gnus-summary-next-unread-article t]
+ ["Previous unread article" gnus-summary-prev-unread-article t]
+ ["Next article" gnus-summary-next-article t]
+ ["Previous article" gnus-summary-prev-article t]
+ ["Next unread subject" gnus-summary-next-unread-subject t]
+ ["Previous unread subject" gnus-summary-prev-unread-subject t]
+ ["Next article same subject" gnus-summary-next-same-subject t]
+ ["Previous article same subject" gnus-summary-prev-same-subject t]
+ ["First unread article" gnus-summary-first-unread-article t]
+ ["Best unread article" gnus-summary-best-unread-article t]
+ ["Go to subject number..." gnus-summary-goto-subject t]
+ ["Go to article number..." gnus-summary-goto-article t]
+ ["Go to the last article" gnus-summary-goto-last-article t]
+ ["Pop article off history" gnus-summary-pop-article t])
+ ("Sort"
+ ["Sort by number" gnus-summary-sort-by-number t]
+ ["Sort by author" gnus-summary-sort-by-author t]
+ ["Sort by subject" gnus-summary-sort-by-subject t]
+ ["Sort by date" gnus-summary-sort-by-date t]
+ ["Sort by score" gnus-summary-sort-by-score t]
+ ["Sort by lines" gnus-summary-sort-by-lines t]
+ ["Sort by characters" gnus-summary-sort-by-chars t]
+ ["Original sort" gnus-summary-sort-by-original t])
+ ("Help"
+ ["Fetch group FAQ" gnus-summary-fetch-faq t]
+ ["Describe group" gnus-summary-describe-group t]
+ ["Read manual" gnus-info-find-node t])
+ ("Modes"
+ ["Pick and read" gnus-pick-mode t]
+ ["Binary" gnus-binary-mode t])
+ ("Regeneration"
+ ["Regenerate" gnus-summary-prepare t]
+ ["Insert cached articles" gnus-summary-insert-cached-articles t]
+ ["Toggle threading" gnus-summary-toggle-threads t])
+ ["See old articles" gnus-summary-insert-old-articles t]
+ ["See new articles" gnus-summary-insert-new-articles t]
+ ["Filter articles..." gnus-summary-execute-command t]
+ ["Run command on subjects..." gnus-summary-universal-argument t]
+ ["Search articles forward..." gnus-summary-search-article-forward t]
+ ["Search articles backward..." gnus-summary-search-article-backward t]
+ ["Toggle line truncation" gnus-summary-toggle-truncation t]
+ ["Expand window" gnus-summary-expand-window t]
+ ["Expire expirable articles" gnus-summary-expire-articles
+ (gnus-check-backend-function
+ 'request-expire-articles gnus-newsgroup-name)]
+ ["Edit local kill file" gnus-summary-edit-local-kill t]
+ ["Edit main kill file" gnus-summary-edit-global-kill t]
+ ["Edit group parameters" gnus-summary-edit-parameters t]
+ ["Customize group parameters" gnus-summary-customize-parameters t]
+ ["Send a bug report" gnus-bug t]
+ ("Exit"
+ ["Catchup and exit" gnus-summary-catchup-and-exit
+ ,@(if (featurep 'xemacs) '(t)
+ '(:help "Mark unread articles in this group as read, then exit"))]
+ ["Catchup all and exit" gnus-summary-catchup-all-and-exit t]
+ ["Catchup and goto next" gnus-summary-catchup-and-goto-next-group t]
+ ["Exit group" gnus-summary-exit
+ ,@(if (featurep 'xemacs) '(t)
+ '(:help "Exit current group, return to group selection mode"))]
+ ["Exit group without updating" gnus-summary-exit-no-update t]
+ ["Exit and goto next group" gnus-summary-next-group t]
+ ["Exit and goto prev group" gnus-summary-prev-group t]
+ ["Reselect group" gnus-summary-reselect-current-group t]
+ ["Rescan group" gnus-summary-rescan-group t]
+ ["Update dribble" gnus-summary-save-newsrc t])))
(gnus-run-hooks 'gnus-summary-menu-hook)))
(setq gnus-newsgroup-data (nconc list gnus-newsgroup-data))
(when offset
(gnus-data-update-list odata offset)))
- ;; Find the last element in the list to be spliced into the main
+ ;; Find the last element in the list to be spliced into the main
;; list.
(while (cdr list)
(setq list (cdr list)))
(defun gnus-article-parent-p (number)
"Say whether this article is a parent or not."
(let ((data (gnus-data-find-list number)))
- (and (cdr data) ; There has to be an article after...
+ (and (cdr data) ; There has to be an article after...
(< (gnus-data-level (car data)) ; And it has to have a higher level.
(gnus-data-level (nth 1 data))))))
;; Saving hidden threads.
-(put 'gnus-save-hidden-threads 'lisp-indent-function 0)
-(put 'gnus-save-hidden-threads 'edebug-form-spec '(body))
-
(defmacro gnus-save-hidden-threads (&rest forms)
"Save hidden threads, eval FORMS, and restore the hidden threads."
(let ((config (make-symbol "config")))
(save-excursion
,@forms)
(gnus-restore-hidden-threads-configuration ,config)))))
+(put 'gnus-save-hidden-threads 'lisp-indent-function 0)
+(put 'gnus-save-hidden-threads 'edebug-form-spec '(body))
(defun gnus-data-compute-positions ()
"Compute the positions of all articles."
;; Nix out all the control chars...
(while (>= (setq i (1- i)) 0)
(aset table i [??]))
- ;; ... but not newline and cr, of course. (cr is necessary for the
+ ;; ... but not newline and cr, of course. (cr is necessary for the
;; selective display).
(aset table ?\n nil)
(aset table ?\r nil)
(aset table i [??]))))
(setq buffer-display-table table)))
+(defun gnus-summary-set-article-display-arrow (pos)
+ "Update the overlay arrow to point to line at position POS."
+ (when (and gnus-summary-display-arrow
+ (boundp 'overlay-arrow-position)
+ (boundp 'overlay-arrow-string))
+ (save-excursion
+ (goto-char pos)
+ (beginning-of-line)
+ (unless overlay-arrow-position
+ (setq overlay-arrow-position (make-marker)))
+ (setq overlay-arrow-string "=>"
+ overlay-arrow-position (set-marker overlay-arrow-position
+ (point)
+ (current-buffer))))))
+
(defun gnus-summary-buffer-name (group)
"Return the summary buffer name of GROUP."
- (concat "*Summary " group "*"))
+ (concat "*Summary " (gnus-group-decoded-name group) "*"))
(defun gnus-summary-setup-buffer (group)
"Initialize summary buffer."
(point) (progn (eval gnus-summary-dummy-line-format-spec) (point))
(list 'gnus-number gnus-tmp-number 'gnus-intangible gnus-tmp-number)))
-(defun gnus-summary-from-or-to-or-newsgroups (header)
- (let ((to (cdr (assq 'To (mail-header-extra header))))
- (newsgroups (cdr (assq 'Newsgroups (mail-header-extra header))))
- (mail-parse-charset gnus-newsgroup-charset)
+(defun gnus-summary-extract-address-component (from)
+ (or (car (funcall gnus-extract-address-components from))
+ from))
+
+(defun gnus-summary-from-or-to-or-newsgroups (header gnus-tmp-from)
+ (let ((mail-parse-charset gnus-newsgroup-charset)
+ ; Is it really necessary to do this next part for each summary line?
+ ; Luckily, doesn't seem to slow things down much.
(mail-parse-ignored-charsets
(save-excursion (set-buffer gnus-summary-buffer)
gnus-newsgroup-ignored-charsets)))
- (cond
- ((and to
- gnus-ignored-from-addresses
- (string-match gnus-ignored-from-addresses
- (mail-header-from header)))
- (concat "-> "
- (or (car (funcall gnus-extract-address-components
- (funcall
- gnus-decode-encoded-word-function to)))
- (funcall gnus-decode-encoded-word-function to))))
- ((and newsgroups
- gnus-ignored-from-addresses
- (string-match gnus-ignored-from-addresses
- (mail-header-from header)))
- (concat "=> " newsgroups))
- (t
- (or (car (funcall gnus-extract-address-components
- (mail-header-from header)))
- (mail-header-from header))))))
+ (or
+ (and gnus-ignored-from-addresses
+ (string-match gnus-ignored-from-addresses gnus-tmp-from)
+ (let ((extra-headers (mail-header-extra header))
+ to
+ newsgroups)
+ (cond
+ ((setq to (cdr (assq 'To extra-headers)))
+ (concat "-> "
+ (gnus-summary-extract-address-component
+ (funcall gnus-decode-encoded-word-function to))))
+ ((setq newsgroups (cdr (assq 'Newsgroups extra-headers)))
+ (concat "=> " newsgroups)))))
+ (gnus-summary-extract-address-component gnus-tmp-from))))
(defun gnus-summary-insert-line (gnus-tmp-header
gnus-tmp-level gnus-tmp-current
(if (or (null gnus-summary-default-score)
(<= (abs (- gnus-tmp-score gnus-summary-default-score))
gnus-summary-zcore-fuzz))
- ? ;Whitespace
+ ? ;Whitespace
(if (< gnus-tmp-score gnus-summary-default-score)
gnus-score-below-mark gnus-score-over-mark)))
+ (gnus-tmp-number (mail-header-number gnus-tmp-header))
(gnus-tmp-replied
(cond (gnus-tmp-process gnus-process-mark)
((memq gnus-tmp-current gnus-newsgroup-cached)
gnus-cached-mark)
(gnus-tmp-replied gnus-replied-mark)
+ ((memq gnus-tmp-current gnus-newsgroup-forwarded)
+ gnus-forwarded-mark)
((memq gnus-tmp-current gnus-newsgroup-saved)
gnus-saved-mark)
+ ((memq gnus-tmp-number gnus-newsgroup-recent)
+ gnus-recent-mark)
+ ((memq gnus-tmp-number gnus-newsgroup-unseen)
+ gnus-unseen-mark)
(t gnus-no-mark)))
(gnus-tmp-from (mail-header-from gnus-tmp-header))
(gnus-tmp-name
(1+ (match-beginning 0)) (1- (match-end 0))))
(t gnus-tmp-from)))
(gnus-tmp-subject (mail-header-subject gnus-tmp-header))
- (gnus-tmp-number (mail-header-number gnus-tmp-header))
(gnus-tmp-opening-bracket (if gnus-tmp-dummy ?\< ?\[))
(gnus-tmp-closing-bracket (if gnus-tmp-dummy ?\> ?\]))
(buffer-read-only nil))
(setq gnus-tmp-name gnus-tmp-from))
(unless (numberp gnus-tmp-lines)
(setq gnus-tmp-lines -1))
- (when (= gnus-tmp-lines -1)
- (setq gnus-tmp-lines "?"))
+ (if (= gnus-tmp-lines -1)
+ (setq gnus-tmp-lines "?")
+ (setq gnus-tmp-lines (number-to-string gnus-tmp-lines)))
(gnus-put-text-property
(point)
(progn (eval gnus-summary-line-format-spec) (point))
(if (or (null gnus-summary-default-score)
(<= (abs (- score gnus-summary-default-score))
gnus-summary-zcore-fuzz))
- ? ;Whitespace
+ ? ;Whitespace
(if (< score gnus-summary-default-score)
gnus-score-below-mark gnus-score-over-mark))
'score))
This may be 0 in some cases -- if none of the articles in
the thread are to be displayed."
(let* ((number
- ;; Fix by Luc Van Eycken <Luc.VanEycken@esat.kuleuven.ac.be>.
+ ;; Fix by Luc Van Eycken <Luc.VanEycken@esat.kuleuven.ac.be>.
(cond
((not (listp thread))
1)
(defun gnus-summary-set-local-parameters (group)
"Go through the local params of GROUP and set all variable specs in that list."
(let ((params (gnus-group-find-parameter group))
+ (vars '(quit-config)) ; Ignore quit-config.
elem)
(while params
(setq elem (car params)
(and (consp elem) ; Has to be a cons.
(consp (cdr elem)) ; The cdr has to be a list.
(symbolp (car elem)) ; Has to be a symbol in there.
- (not (memq (car elem) '(quit-config))) ; Ignore quit-config.
+ (not (memq (car elem) vars))
(ignore-errors ; So we set it.
+ (push (car elem) vars)
(make-local-variable (car elem))
(set (car elem) (eval (nth 1 elem))))))))
;; (when (and (not (gnus-group-native-p group))
;; (not (gnus-gethash group gnus-newsrc-hashtb)))
;; (error "Dead non-native groups can't be entered"))
- (gnus-message 5 "Retrieving newsgroup: %s..."
+ (gnus-message 5 "Retrieving newsgroup: %s..."
(gnus-group-decoded-name group))
(let* ((new-group (gnus-summary-setup-buffer group))
(quit-config (gnus-group-quit-config group))
(gnus-group-next-unread-group 1))
(gnus-handle-ephemeral-exit quit-config)))
(let ((grpinfo (gnus-get-info group)))
- (if (null (gnus-info-read grpinfo))
- (gnus-message 3 "Group %s contains no messages"
+ (if (null (gnus-info-read grpinfo))
+ (gnus-message 3 "Group %s contains no messages"
(gnus-group-decoded-name group))
- (gnus-message 3 "Can't select group")))
+ (gnus-message 3 "Can't select group")))
nil)
;; The user did a `C-g' while prompting for number of articles,
;; so we exit this group.
(gnus-summary-hide-all-threads))
(when kill-buffer
(gnus-kill-or-deaden-summary kill-buffer))
+ (gnus-summary-auto-select-subject)
;; Show first unread article if requested.
(if (and (not no-article)
(not no-display)
gnus-auto-select-first)
(progn
(gnus-configure-windows 'summary)
- (cond
- ((eq gnus-auto-select-first 'best)
- (gnus-summary-best-unread-article))
- ((eq gnus-auto-select-first t)
- (gnus-summary-first-unread-article))
- ((gnus-functionp gnus-auto-select-first)
- (funcall gnus-auto-select-first))))
- ;; Don't select any articles, just move point to the first
- ;; article in the group.
- (goto-char (point-min))
+ (gnus-summary-goto-article (gnus-summary-article-number)))
+ ;; Don't select any articles.
(gnus-summary-position-point)
(gnus-configure-windows 'summary 'force)
(gnus-set-mode-line 'summary))
(gnus-run-hooks 'gnus-summary-prepared-hook)
t)))))
+(defun gnus-summary-auto-select-subject ()
+ "Select the subject line on initial group entry."
+ (goto-char (point-min))
+ (cond
+ ((eq gnus-auto-select-subject 'best)
+ (gnus-summary-best-unread-subject))
+ ((eq gnus-auto-select-subject 'unread)
+ (gnus-summary-first-unread-subject))
+ ((eq gnus-auto-select-subject 'unseen)
+ (gnus-summary-first-unseen-subject))
+ ((eq gnus-auto-select-subject 'first)
+ ;; Do nothing.
+ )
+ ((gnus-functionp gnus-auto-select-subject)
+ (funcall gnus-auto-select-subject))))
+
(defun gnus-summary-prepare ()
"Generate the summary buffer."
(interactive)
(if (and gnus-summary-gather-exclude-subject
(string-match gnus-summary-gather-exclude-subject subject))
- nil ; This article shouldn't be gathered
+ nil ; This article shouldn't be gathered
subject))
(defun gnus-summary-simplify-subject-query ()
(setq threads nil)
(throw 'infloop t))
(unless (car (symbol-value refs))
- ;; These threads do not refer back to any other articles,
+ ;; These threads do not refer back to any other articles,
;; so they're roots.
(setq threads (append (cdr (symbol-value refs)) threads))))
gnus-newsgroup-dependencies)))
(when parent
(delq thread parent)))
(if (gnus-summary-insert-subject id header)
- ;; Set the (possibly) new article number in the data structure.
+ ;; Set the (possibly) new article number in the data structure.
(gnus-data-set-number data (gnus-id-to-article id))
(setcar thread old)
nil))))
(setq thread (gnus-remove-thread id)))
(setq old-pos (gnus-point-at-bol))
(setq current (save-excursion
- (and (zerop (forward-line -1))
+ (and (re-search-backward "[\r\n]" nil t)
(gnus-summary-article-number))))
;; If this is a gathered thread, we have to go some re-gathering.
(when (stringp (car thread))
(or (cdr (assq type (mail-header-extra (or header gnus-tmp-header))))
""))
+(defvar gnus-tmp-thread-tree-header-string "")
+
+(defvar gnus-sum-thread-tree-root "> "
+ "With %B spec, used for the root of a thread.
+If nil, use subject instead.")
+(defvar gnus-sum-thread-tree-single-indent ""
+ "With %B spec, used for a thread with just one message.
+If nil, use subject instead.")
+(defvar gnus-sum-thread-tree-vertical "| "
+ "With %B spec, used for drawing a vertical line.")
+(defvar gnus-sum-thread-tree-indent " "
+ "With %B spec, used for indenting.")
+(defvar gnus-sum-thread-tree-leaf-with-other "+-> "
+ "With %B spec, used for a leaf with brothers.")
+(defvar gnus-sum-thread-tree-single-leaf "\\-> "
+ "With %B spec, used for a leaf without brothers.")
+
(defun gnus-summary-prepare-threads (threads)
"Prepare summary buffer from THREADS and indentation LEVEL.
THREADS is either a list of `(PARENT [(CHILD1 [(GRANDCHILD ...]...) ...])'
gnus-tmp-replied gnus-tmp-subject-or-nil
gnus-tmp-dummy gnus-tmp-indentation gnus-tmp-lines gnus-tmp-score
gnus-tmp-score-char gnus-tmp-from gnus-tmp-name
- gnus-tmp-number gnus-tmp-opening-bracket gnus-tmp-closing-bracket)
+ gnus-tmp-number gnus-tmp-opening-bracket gnus-tmp-closing-bracket
+ tree-stack)
(setq gnus-tmp-prev-subject nil)
;; the stack.
(setq state (car stack)
gnus-tmp-level (car state)
- thread (cdr state)
+ tree-stack (cadr state)
+ thread (caddr state)
stack (cdr stack)
gnus-tmp-header (caar thread))))
(if (or (null gnus-summary-default-score)
(<= (abs (- gnus-tmp-score gnus-summary-default-score))
gnus-summary-zcore-fuzz))
- ? ;Whitespace
+ ? ;Whitespace
(if (< gnus-tmp-score gnus-summary-default-score)
gnus-score-below-mark gnus-score-over-mark))
gnus-tmp-replied
gnus-forwarded-mark)
((memq number gnus-newsgroup-saved)
gnus-saved-mark)
+ ((memq number gnus-newsgroup-recent)
+ gnus-recent-mark)
+ ((memq number gnus-newsgroup-unseen)
+ gnus-unseen-mark)
(t gnus-no-mark))
gnus-tmp-from (mail-header-from gnus-tmp-header)
gnus-tmp-name
((string-match "(.+)" gnus-tmp-from)
(substring gnus-tmp-from
(1+ (match-beginning 0)) (1- (match-end 0))))
- (t gnus-tmp-from)))
+ (t gnus-tmp-from))
+ gnus-tmp-thread-tree-header-string
+ (cond
+ ((not gnus-show-threads) "")
+ ((zerop gnus-tmp-level)
+ (if (cdar thread)
+ (or gnus-sum-thread-tree-root subject)
+ (or gnus-sum-thread-tree-single-indent subject)))
+ (t
+ (concat (apply 'concat
+ (mapcar (lambda (item)
+ (if (= item 1)
+ gnus-sum-thread-tree-vertical
+ gnus-sum-thread-tree-indent))
+ (cdr (reverse tree-stack))))
+ (if (nth 1 thread)
+ gnus-sum-thread-tree-leaf-with-other
+ gnus-sum-thread-tree-single-leaf)))))
(when (string= gnus-tmp-name "")
(setq gnus-tmp-name gnus-tmp-from))
(unless (numberp gnus-tmp-lines)
(setq gnus-tmp-lines -1))
- (when (= gnus-tmp-lines -1)
- (setq gnus-tmp-lines "?"))
+ (if (= gnus-tmp-lines -1)
+ (setq gnus-tmp-lines "?")
+ (setq gnus-tmp-lines (number-to-string gnus-tmp-lines)))
(gnus-put-text-property
(point)
(progn (eval gnus-summary-line-format-spec) (point))
(setq gnus-tmp-prev-subject subject)))
(when (nth 1 thread)
- (push (cons (max 0 gnus-tmp-level) (nthcdr 1 thread)) stack))
+ (push (list (max 0 gnus-tmp-level)
+ (copy-list tree-stack)
+ (nthcdr 1 thread))
+ stack))
+ (push (if (nth 1 thread) 1 0) tree-stack)
(incf gnus-tmp-level)
(setq threads (if thread-end nil (cdar thread)))
(unless threads
(let* ((entry (gnus-gethash group gnus-newsrc-hashtb))
;;!!! Dirty hack; should be removed.
(gnus-summary-ignore-duplicates
- (if (eq (car (gnus-find-method-for-group group)) 'nnvirtual)
+ (if (eq (car (gnus-find-method-for-group group)) 'nnvirtual)
t
gnus-summary-ignore-duplicates))
(info (nth 2 entry))
articles fetched-articles cached)
(unless (gnus-check-server
- (setq gnus-current-select-method
- (gnus-find-method-for-group group)))
+ (set (make-local-variable 'gnus-current-select-method)
+ (gnus-find-method-for-group group)))
(error "Couldn't open server"))
(or (and entry (not (eq (car entry) t))) ; Either it's active...
(error "Couldn't request group %s: %s"
group (gnus-status-message group)))
- (setq gnus-newsgroup-name group)
- (setq gnus-newsgroup-unselected nil)
- (setq gnus-newsgroup-unreads (gnus-list-of-unread-articles group))
- (gnus-summary-setup-default-charset)
+ (setq gnus-newsgroup-name group
+ gnus-newsgroup-unselected nil
+ gnus-newsgroup-unreads (gnus-list-of-unread-articles group))
- ;; Adjust and set lists of article marks.
- (when info
- (gnus-adjust-marked-articles info))
+ (let ((display (gnus-group-find-parameter group 'display)))
+ (setq gnus-newsgroup-display
+ (cond
+ ((not (zerop (or (car-safe read-all) 0)))
+ ;; The user entered the group with C-u SPC/RET, let's show
+ ;; all articles.
+ 'gnus-not-ignore)
+ ((eq display 'all)
+ 'gnus-not-ignore)
+ ((arrayp display)
+ (gnus-summary-display-make-predicate (mapcar 'identity display)))
+ ((numberp display)
+ ;; The following is probably the "correct" solution, but
+ ;; it makes Gnus fetch all headers and then limit the
+ ;; articles (which is slow), so instead we hack the
+ ;; select-articles parameter instead. -- Simon Josefsson
+ ;; <jas@kth.se>
+ ;;
+ ;; (gnus-byte-compile
+ ;; `(lambda () (> number ,(- (cdr (gnus-active group))
+ ;; display)))))
+ (setq select-articles
+ (gnus-uncompress-range
+ (cons (let ((tmp (- (cdr (gnus-active group)) display)))
+ (if (> tmp 0)
+ tmp
+ 1))
+ (cdr (gnus-active group)))))
+ nil)
+ (t
+ nil))))
+
+ (gnus-summary-setup-default-charset)
;; Kludge to avoid having cached articles nixed out in virtual groups.
(when (gnus-virtual-group-p group)
(gnus-update-read-articles group gnus-newsgroup-unreads)
+ ;; Adjust and set lists of article marks.
+ (when info
+ (gnus-adjust-marked-articles info))
+
(if (setq articles select-articles)
(setq gnus-newsgroup-unselected
(gnus-sorted-intersection
;; Set the initial limit.
(setq gnus-newsgroup-limit (copy-sequence articles))
;; Remove canceled articles from the list of unread articles.
+ (setq fetched-articles
+ (mapcar (lambda (headers) (mail-header-number headers))
+ gnus-newsgroup-headers))
+ (setq gnus-newsgroup-articles fetched-articles)
(setq gnus-newsgroup-unreads
(gnus-set-sorted-intersection
- gnus-newsgroup-unreads
- (setq fetched-articles
- (mapcar (lambda (headers) (mail-header-number headers))
- gnus-newsgroup-headers))))
+ gnus-newsgroup-unreads fetched-articles))
+
+ ;; The `seen' marks are treated specially.
+ (if (not gnus-newsgroup-seen)
+ (setq gnus-newsgroup-unseen gnus-newsgroup-articles)
+ (dolist (article gnus-newsgroup-articles)
+ (unless (gnus-member-of-range article gnus-newsgroup-seen)
+ (push article gnus-newsgroup-unseen)))
+ (setq gnus-newsgroup-unseen (nreverse gnus-newsgroup-unseen)))
+
;; Removed marked articles that do not exist.
(gnus-update-missing-marks
(gnus-sorted-complement fetched-articles articles))
;; GROUP is successfully selected.
(or gnus-newsgroup-headers t)))))
+(defun gnus-summary-display-make-predicate (display)
+ (require 'gnus-agent)
+ (when (= (length display) 1)
+ (setq display (car display)))
+ (unless gnus-summary-display-cache
+ (dolist (elem (append (list (cons 'read 'read)
+ (cons 'unseen 'unseen))
+ gnus-article-mark-lists))
+ (push (cons (cdr elem)
+ (gnus-byte-compile
+ `(lambda () (gnus-article-marked-p ',(cdr elem)))))
+ gnus-summary-display-cache)))
+ (let ((gnus-category-predicate-alist gnus-summary-display-cache))
+ (gnus-get-predicate display)))
+
+;; Uses the dynamically bound `number' variable.
+(defvar number)
+(defun gnus-article-marked-p (type &optional article)
+ (let ((article (or article number)))
+ (cond
+ ((eq type 'tick)
+ (memq article gnus-newsgroup-marked))
+ ((eq type 'unsend)
+ (memq article gnus-newsgroup-unsendable))
+ ((eq type 'undownload)
+ (memq article gnus-newsgroup-undownloaded))
+ ((eq type 'download)
+ (memq article gnus-newsgroup-downloadable))
+ ((eq type 'unread)
+ (memq article gnus-newsgroup-unreads))
+ ((eq type 'read)
+ (memq article gnus-newsgroup-reads))
+ ((eq type 'dormant)
+ (memq article gnus-newsgroup-dormant) )
+ ((eq type 'expire)
+ (memq article gnus-newsgroup-expirable))
+ ((eq type 'reply)
+ (memq article gnus-newsgroup-replied))
+ ((eq type 'killed)
+ (memq article gnus-newsgroup-killed))
+ ((eq type 'bookmark)
+ (assq article gnus-newsgroup-bookmarks))
+ ((eq type 'score)
+ (assq article gnus-newsgroup-scored))
+ ((eq type 'save)
+ (memq article gnus-newsgroup-saved))
+ ((eq type 'cache)
+ (memq article gnus-newsgroup-cached))
+ ((eq type 'forward)
+ (memq article gnus-newsgroup-forwarded))
+ ((eq type 'seen)
+ (not (memq article gnus-newsgroup-unseen)))
+ ((eq type 'recent)
+ (memq article gnus-newsgroup-recent))
+ (t t))))
+
(defun gnus-articles-to-read (group &optional read-all)
"Find out what articles the user wants to read."
(let* ((articles
(if (or read-all
(and (zerop (length gnus-newsgroup-marked))
(zerop (length gnus-newsgroup-unreads)))
- (eq (gnus-group-find-parameter group 'display)
- 'all))
+ (eq gnus-newsgroup-display 'gnus-not-ignore))
+ ;; We want to select the headers for all the articles in
+ ;; the group, so we select either all the active
+ ;; articles in the group, or (if that's nil), the
+ ;; articles in the cache.
(or
(gnus-uncompress-range (gnus-active group))
(gnus-cache-articles-in-group group))
+ ;; Select only the "normal" subset of articles.
(sort (append gnus-newsgroup-dormant gnus-newsgroup-marked
(copy-sequence gnus-newsgroup-unreads))
'<)))
(read-string
(format
"How many articles from %s (default %d): "
- (gnus-limit-string gnus-newsgroup-name 35)
+ (gnus-limit-string
+ (gnus-group-decoded-name gnus-newsgroup-name)
+ 35)
number))))
(if (string-match "^[ \t]*$" input) number input)))
((and (> scored marked) (< scored number)
(read-string
(format "%s %s (%d scored, %d total): "
"How many articles from"
- group scored number))))
+ (gnus-group-decoded-name group)
+ scored number))))
(if (string-match "^[ \t]*$" input)
number input)))
(t number))
(setq marks (cdr marks)))
out))
+(defun gnus-article-mark-to-type (mark)
+ "Return the type of MARK."
+ (or (cadr (assq mark gnus-article-special-mark-lists))
+ 'list))
+
+(defun gnus-article-unpropagatable-p (mark)
+ "Return whether MARK should be propagated to backend."
+ (memq mark gnus-article-unpropagated-mark-lists))
+
(defun gnus-adjust-marked-articles (info)
"Set all article lists and remove all marks that are no longer valid."
(let* ((marked-lists (gnus-info-marks info))
(min (car active))
(max (cdr active))
(types gnus-article-mark-lists)
- (uncompressed '(score bookmark killed))
- marks var articles article mark)
-
- (while marked-lists
- (setq marks (pop marked-lists))
- (set (setq var (intern (format "gnus-newsgroup-%s"
- (car (rassq (setq mark (car marks))
- types)))))
- (if (memq (car marks) uncompressed) (cdr marks)
- (gnus-uncompress-range (cdr marks))))
+ marks var articles article mark mark-type)
- (setq articles (symbol-value var))
+ (dolist (marks marked-lists)
+ (setq mark (car marks)
+ mark-type (gnus-article-mark-to-type mark)
+ var (intern (format "gnus-newsgroup-%s" (car (rassq mark types)))))
- ;; All articles have to be subsets of the active articles.
+ ;; We set the variable according to the type of the marks list,
+ ;; and then adjust the marks to a subset of the active articles.
(cond
;; Adjust "simple" lists.
- ((memq mark '(tick dormant expire reply save))
- (while articles
- (when (or (< (setq article (pop articles)) min) (> article max))
- (set var (delq article (symbol-value var))))))
+ ((eq mark-type 'list)
+ (set var (setq articles (gnus-uncompress-range (cdr marks))))
+ (when (memq mark '(tick dormant expire reply save))
+ (while articles
+ (when (or (< (setq article (pop articles)) min) (> article max))
+ (set var (delq article (symbol-value var)))))))
;; Adjust assocs.
- ((memq mark uncompressed)
+ ((eq mark-type 'tuple)
+ (set var (setq articles (cdr marks)))
(when (not (listp (cdr (symbol-value var))))
(set var (list (symbol-value var))))
(when (not (listp (cdr articles)))
(when (or (not (consp (setq article (pop articles))))
(< (car article) min)
(> (car article) max))
- (set var (delq article (symbol-value var))))))))))
+ (set var (delq article (symbol-value var))))))
+ ;; Adjust ranges (sloppily).
+ ((eq mark-type 'range)
+ (cond
+ ((eq mark 'seen)
+ (setq articles (cdr marks))
+ (while (and articles
+ (or (and (consp (car articles))
+ (> min (cdar articles)))
+ (and (numberp (car articles))
+ (> min (car articles)))))
+ (pop articles))
+ (set var articles))))))))
(defun gnus-update-missing-marks (missing)
"Go through the list of MISSING articles and remove them from the mark lists."
(when missing
- (let ((types gnus-article-mark-lists)
- var m)
+ (let (var m)
;; Go through all types.
- (while types
- (setq var (intern (format "gnus-newsgroup-%s" (car (pop types)))))
- (when (symbol-value var)
- ;; This list has articles. So we delete all missing articles
- ;; from it.
- (setq m missing)
- (while m
- (set var (delq (pop m) (symbol-value var)))))))))
+ (dolist (elem gnus-article-mark-lists)
+ (when (eq (gnus-article-mark-to-type (cdr elem)) 'list)
+ (setq var (intern (format "gnus-newsgroup-%s" (car elem))))
+ (when (symbol-value var)
+ ;; This list has articles. So we delete all missing
+ ;; articles from it.
+ (setq m missing)
+ (while m
+ (set var (delq (pop m) (symbol-value var))))))))))
(defun gnus-update-marks ()
"Enter the various lists of marked articles into the newsgroup info list."
(let ((types gnus-article-mark-lists)
(info (gnus-get-info gnus-newsgroup-name))
- (uncompressed '(score bookmark killed))
type list newmarked symbol delta-marks)
(when info
;; Add all marks lists to the list of marks lists.
(while (setq type (pop types))
(setq list (symbol-value
(setq symbol
- (intern (format "gnus-newsgroup-%s"
- (car type))))))
+ (intern (format "gnus-newsgroup-%s" (car type))))))
(when list
;; Get rid of the entries of the articles that have the
(setq arts (cdr arts)))
(setq list (cdr all)))))
- (unless (memq (cdr type) uncompressed)
+ (when (eq (cdr type) 'seen)
+ (setq list (gnus-range-add list gnus-newsgroup-unseen)))
+
+ (when (eq (gnus-article-mark-to-type (cdr type)) 'list)
(setq list (gnus-compress-sequence (set symbol (sort list '<)) t)))
- (when (gnus-check-backend-function
- 'request-set-mark gnus-newsgroup-name)
- ;; propagate flags to server, with the following exceptions:
- ;; uncompressed:s are not proper flags (they are cons cells)
- ;; cache is a internal gnus flag
- ;; download are local to one gnus installation (well)
- ;; unsend are for nndraft groups only
- ;; xxx: generality of this? this suits nnimap anyway
- (unless (memq (cdr type) (append '(cache download unsend)
- uncompressed))
- (let* ((old (cdr (assq (cdr type) (gnus-info-marks info))))
- (del (gnus-remove-from-range (gnus-copy-sequence old) list))
- (add (gnus-remove-from-range
- (gnus-copy-sequence list) old)))
- (when add
- (push (list add 'add (list (cdr type))) delta-marks))
- (when del
- (push (list del 'del (list (cdr type))) delta-marks)))))
+ (when (and (gnus-check-backend-function
+ 'request-set-mark gnus-newsgroup-name)
+ (not (gnus-article-unpropagatable-p (cdr type))))
+ (let* ((old (cdr (assq (cdr type) (gnus-info-marks info))))
+ (del (gnus-remove-from-range (gnus-copy-sequence old) list))
+ (add (gnus-remove-from-range
+ (gnus-copy-sequence list) old)))
+ (when add
+ (push (list add 'add (list (cdr type))) delta-marks))
+ (when del
+ (push (list del 'del (list (cdr type))) delta-marks))))
(when list
(push (cons (cdr type) list) newmarked)))
;; We evaluate this in the summary buffer since these
;; variables are buffer-local to that buffer.
(set-buffer gnus-summary-buffer)
- ;; We bind all these variables that are used in the `eval' form
+ ;; We bind all these variables that are used in the `eval' form
;; below.
(let* ((mformat (symbol-value
(intern
(format "gnus-%s-mode-line-format-spec" where))))
- (gnus-tmp-group-name (gnus-group-decoded-name
+ (gnus-tmp-group-name (gnus-group-decoded-name
gnus-newsgroup-name))
(gnus-tmp-article-number (or gnus-current-article 0))
(gnus-tmp-unread gnus-newsgroup-unreads)
(mail-header-subject gnus-current-headers))
""))
bufname-length max-len
- gnus-tmp-header);; passed as argument to any user-format-funcs
+ gnus-tmp-header) ;; passed as argument to any user-format-funcs
(setq mode-string (eval mformat))
(setq bufname-length (if (string-match "%b" mode-string)
(- (length
(gnus-info-set-marks ',info ',(gnus-info-marks info) t)
(gnus-info-set-read ',info ',(gnus-info-read info))
(gnus-get-unread-articles-in-group ',info (gnus-active ,group))
+ (gnus-request-set-mark ,group (list (list ',range 'del '(read))))
(gnus-group-update-group ,group t))))
;; Add the read articles to the range.
(gnus-info-set-read info range)
+ (gnus-request-set-mark group (list (list range 'add '(read))))
;; Then we have to re-compute how many unread
;; articles there are in this group.
(when active
;; Subject.
(progn
(goto-char p)
- (if (search-forward "\nsubject: " nil t)
+ (if (search-forward "\nsubject:" nil t)
(funcall gnus-decode-encoded-word-function
(nnheader-header-value))
"(none)"))
;; From.
(progn
(goto-char p)
- (if (or (search-forward "\nfrom: " nil t)
- (search-forward "\nfrom:" nil t))
+ (if (search-forward "\nfrom:" nil t)
(funcall gnus-decode-encoded-word-function
(nnheader-header-value))
"(nobody)"))
;; Date.
(progn
(goto-char p)
- (if (search-forward "\ndate: " nil t)
+ (if (search-forward "\ndate:" nil t)
(nnheader-header-value) ""))
;; Message-ID.
(progn
;; References.
(progn
(goto-char p)
- (if (search-forward "\nreferences: " nil t)
+ (if (search-forward "\nreferences:" nil t)
(progn
(setq end (point))
(prog1
;; Get the references from the in-reply-to header if there
;; were no references and the in-reply-to header looks
;; promising.
- (if (and (search-forward "\nin-reply-to: " nil t)
+ (if (and (search-forward "\nin-reply-to:" nil t)
(setq in-reply-to (nnheader-header-value))
(string-match "<[^>]+>" in-reply-to))
(let (ref2)
;; Xref.
(progn
(goto-char p)
- (and (search-forward "\nxref: " nil t)
+ (and (search-forward "\nxref:" nil t)
(nnheader-header-value)))
;; Extra.
(when gnus-extra-headers
(while extra
(goto-char p)
(when (search-forward
- (concat "\n" (symbol-name (car extra)) ": ") nil t)
+ (concat "\n" (symbol-name (car extra)) ":") nil t)
(push (cons (car extra) (nnheader-header-value))
out))
(pop extra))
(let ((gnus-nov-is-evil t))
(nconc
(nreverse headers)
- (when (gnus-retrieve-headers sequence group)
+ (when (eq (gnus-retrieve-headers sequence group) 'headers)
(gnus-get-newsgroup-headers))))))))
(defun gnus-article-get-xrefs ()
If `gnus-auto-center-summary' is nil, or the article buffer isn't
displayed, no centering will be performed."
;; Suggested by earle@mahendo.JPL.NASA.GOV (Greg Earle).
- ;; Recenter only when requested. Suggested by popovich@park.cs.columbia.edu.
+;; Recenter only when requested. Suggested by popovich@park.cs.columbia.edu.
(interactive)
(let* ((top (cond ((< (window-height) 4) 0)
((< (window-height) 7) 1)
(when gnus-auto-center-summary
(when (get-buffer-window gnus-article-buffer)
;; Only do recentering when the article buffer is displayed,
- ;; Set the window start to either `bottom', which is the biggest
+ ;; Set the window start to either `bottom', which is the biggest
;; possible valid number, or the second line from the top,
;; whichever is the least.
(let ((top-pos (save-excursion (forward-line (- top)) (point))))
(let* ((group gnus-newsgroup-name)
(quit-config (gnus-group-quit-config gnus-newsgroup-name))
(mode major-mode)
- (group-point nil)
+ (group-point nil)
(buf (current-buffer)))
(unless quit-config
;; Do adaptive scoring, and possibly save score files.
(progn
(gnus-deaden-summary)
(setq mode nil))
- ;; We set all buffer-local variables to nil. It is unclear why
+ ;; We set all buffer-local variables to nil. It is unclear why
;; this is needed, but if we don't, buffer-local variables are
;; not garbage-collected, it seems. This would the lead to en
;; ever-growing Emacs.
(when (equal (gnus-group-group-name) group)
(gnus-group-next-unread-group 1))
(when quit-config
- (gnus-handle-ephemeral-exit quit-config)))))
+ (gnus-handle-ephemeral-exit quit-config)))))
(defun gnus-handle-ephemeral-exit (quit-config)
"Handle movement when leaving an ephemeral group.
(gnus-configure-windows 'group 'force)
(set-buffer (car quit-config))
(cond ((eq major-mode 'gnus-summary-mode)
- (gnus-set-global-variables))
- ((eq major-mode 'gnus-article-mode)
- (save-excursion
- ;; The `gnus-summary-buffer' variable may point
- ;; to the old summary buffer when using a single
- ;; article buffer.
- (unless (gnus-buffer-live-p gnus-summary-buffer)
- (set-buffer gnus-group-buffer))
- (set-buffer gnus-summary-buffer)
- (gnus-set-global-variables))))
+ (gnus-set-global-variables))
+ ((eq major-mode 'gnus-article-mode)
+ (save-excursion
+ ;; The `gnus-summary-buffer' variable may point
+ ;; to the old summary buffer when using a single
+ ;; article buffer.
+ (unless (gnus-buffer-live-p gnus-summary-buffer)
+ (set-buffer gnus-group-buffer))
+ (set-buffer gnus-summary-buffer)
+ (gnus-set-global-variables))))
(if (or (eq (cdr quit-config) 'article)
- (eq (cdr quit-config) 'pick))
- (progn
- ;; The current article may be from the ephemeral group
- ;; thus it is best that we reload this article
- (gnus-summary-show-article)
- (if (and (boundp 'gnus-pick-mode) (symbol-value 'gnus-pick-mode))
- (gnus-configure-windows 'pick 'force)
- (gnus-configure-windows (cdr quit-config) 'force)))
+ (eq (cdr quit-config) 'pick))
+ (progn
+ ;; The current article may be from the ephemeral group
+ ;; thus it is best that we reload this article
+ (gnus-summary-show-article)
+ (if (and (boundp 'gnus-pick-mode) (symbol-value 'gnus-pick-mode))
+ (gnus-configure-windows 'pick 'force)
+ (gnus-configure-windows (cdr quit-config) 'force)))
(gnus-configure-windows (cdr quit-config) 'force))
(when (eq major-mode 'gnus-summary-mode)
(gnus-summary-next-subject 1 nil t)
(let ((current-group gnus-newsgroup-name)
(current-buffer (current-buffer))
entered)
- ;; First we semi-exit this group to update Xrefs and all variables.
+ ;; First we semi-exit this group to update Xrefs and all variables.
;; We can't do a real exit, because the window conf must remain
;; the same in case the user is prompted for info, and we don't
;; want the window conf to change before that...
;; Walking around summary lines.
-(defun gnus-summary-first-subject (&optional unread undownloaded)
+(defun gnus-summary-first-subject (&optional unread undownloaded unseen)
"Go to the first unread subject.
If UNREAD is non-nil, go to the first unread article.
Returns the article selected or nil if there are no unread articles."
(and (not (and undownloaded
(eq gnus-undownloaded-mark
(gnus-data-mark (car data)))))
+ (not (and unseen
+ (memq (car data) gnus-newsgroup-unseen)))
(not (gnus-data-unread-p (car data)))))
(setq data (cdr data)))
(when data
(unless silent
(gnus-message 3 "Can't find article %d" article))
nil)
- (goto-char (gnus-data-pos data))
+ (let ((pt (gnus-data-pos data)))
+ (goto-char pt)
+ (gnus-summary-set-article-display-arrow pt))
(gnus-summary-position-point)
article)))
(unless (eq major-mode 'gnus-summary-mode)
(set-buffer gnus-summary-buffer))
(let ((article (or article (gnus-summary-article-number)))
- (all-headers (not (not all-headers))) ;Must be T or NIL.
+ (all-headers (not (not all-headers))) ;Must be t or nil.
gnus-summary-display-article-function)
(and (not pseudo)
(gnus-summary-article-pseudo-p article)
(or (null gnus-current-article)
(not (eq gnus-current-article article))))
force)
- ;; The requested article is different from the current article.
+ ;; The requested article is different from the current article.
(progn
(gnus-summary-display-article article all-headers)
(when (gnus-buffer-live-p gnus-article-buffer)
- (with-current-buffer gnus-article-buffer
+ (with-current-buffer gnus-article-buffer
(if (not gnus-article-decoded-p) ;; a local variable
(mm-disable-multibyte-mule4))))
(when (or all-headers gnus-show-all-headers)
(gnus-summary-first-subject t))
(gnus-summary-position-point)))
+(defun gnus-summary-first-unseen-subject ()
+ "Place the point on the subject line of the first unseen article.
+Return nil if there are no unseen articles."
+ (interactive)
+ (prog1
+ (when (gnus-summary-first-subject t t t)
+ (gnus-summary-show-thread)
+ (gnus-summary-first-subject t t t))
+ (gnus-summary-position-point)))
+
(defun gnus-summary-first-article ()
"Select the first article.
Return nil if there are no articles."
(gnus-summary-display-article (gnus-summary-article-number)))
(gnus-summary-position-point)))
-(defun gnus-summary-best-unread-article ()
- "Select the unread article with the highest score."
+(defun gnus-summary-best-unread-article (&optional arg)
+ "Select the unread article with the highest score.
+If given a prefix argument, select the next unread article that has a
+score higher than the default score."
+ (interactive "P")
+ (let ((article (if arg
+ (gnus-summary-better-unread-subject)
+ (gnus-summary-best-unread-subject))))
+ (if article
+ (gnus-summary-goto-article article)
+ (error "No unread articles"))))
+
+(defun gnus-summary-best-unread-subject ()
+ "Select the unread subject with the highest score."
(interactive)
(let ((best -1000000)
(data gnus-newsgroup-data)
(setq best score
article (gnus-data-number (car data))))
(setq data (cdr data)))
- (prog1
- (if article
- (gnus-summary-goto-article article)
- (error "No unread articles"))
- (gnus-summary-position-point))))
+ (when article
+ (gnus-summary-goto-subject article))
+ (gnus-summary-position-point)
+ article))
+
+(defun gnus-summary-better-unread-subject ()
+ "Select the first unread subject that has a score over the default score."
+ (interactive)
+ (let ((data gnus-newsgroup-data)
+ article score)
+ (while (and (setq article (gnus-data-number (car data)))
+ (or (gnus-data-read-p (car data))
+ (not (> (gnus-summary-article-score article)
+ gnus-summary-default-score))))
+ (setq data (cdr data)))
+ (when article
+ (gnus-summary-goto-subject article))
+ (gnus-summary-position-point)
+ article))
(defun gnus-summary-last-subject ()
"Go to the last displayed subject line in the group."
(gnus-summary-limit nil 'pop)
(gnus-summary-position-point)))
-(defun gnus-summary-limit-to-subject (subject &optional header)
- "Limit the summary buffer to articles that have subjects that match a regexp."
- (interactive "sLimit to subject (regexp): ")
+(defun gnus-summary-limit-to-subject (subject &optional header not-matching)
+ "Limit the summary buffer to articles that have subjects that match a regexp.
+If NOT-MATCHING, excluding articles that have subjects that match a regexp."
+ (interactive
+ (list (read-string (if current-prefix-arg
+ "Exclude subject (regexp): "
+ "Limit to subject (regexp): "))
+ nil current-prefix-arg))
(unless header
(setq header "subject"))
(when (not (equal "" subject))
(prog1
(let ((articles (gnus-summary-find-matching
- (or header "subject") subject 'all)))
+ (or header "subject") subject 'all nil nil
+ not-matching)))
(unless articles
(error "Found no matches for \"%s\"" subject))
(gnus-summary-limit articles))
(gnus-summary-position-point))))
-(defun gnus-summary-limit-to-author (from)
- "Limit the summary buffer to articles that have authors that match a regexp."
- (interactive "sLimit to author (regexp): ")
- (gnus-summary-limit-to-subject from "from"))
+(defun gnus-summary-limit-to-author (from &optional not-matching)
+ "Limit the summary buffer to articles that have authors that match a regexp.
+If NOT-MATCHING, excluding articles that have authors that match a regexp."
+ (interactive
+ (list (read-string (if current-prefix-arg
+ "Exclude author (regexp): "
+ "Limit to author (regexp): "))
+ current-prefix-arg))
+ (gnus-summary-limit-to-subject from "from" not-matching))
(defun gnus-summary-limit-to-age (age &optional younger-p)
"Limit the summary buffer to articles that are older than (or equal) AGE days.
(when (> (length days) 0)
(setq days (read days)))
(if (numberp days)
- (setq days-got t)
+ (progn
+ (setq days-got t)
+ (if (< days 0)
+ (progn
+ (setq younger (not younger))
+ (setq days (* days -1)))))
(message "Please enter a number.")
(sleep-for 1)))
(list days younger)))
(gnus-summary-limit (nreverse articles)))
(gnus-summary-position-point)))
-(defun gnus-summary-limit-to-extra (header regexp)
+(defun gnus-summary-limit-to-extra (header regexp &optional not-matching)
"Limit the summary buffer to articles that match an 'extra' header."
(interactive
(let ((header
(intern
(gnus-completing-read
(symbol-name (car gnus-extra-headers))
- "Limit extra header:"
+ (if current-prefix-arg
+ "Exclude extra header:"
+ "Limit extra header:")
(mapcar (lambda (x)
(cons (symbol-name x) x))
gnus-extra-headers)
nil
t))))
(list header
- (read-string (format "Limit to header %s (regexp): " header)))))
+ (read-string (format "%s header %s (regexp): "
+ (if current-prefix-arg "Exclude" "Limit to")
+ header))
+ current-prefix-arg)))
(when (not (equal "" regexp))
(prog1
(let ((articles (gnus-summary-find-matching
- (cons 'extra header) regexp 'all)))
+ (cons 'extra header) regexp 'all nil nil
+ not-matching)))
(unless articles
(error "Found no matches for \"%s\"" regexp))
(gnus-summary-limit articles))
(gnus-summary-position-point))))
+(defun gnus-summary-limit-to-display-predicate ()
+ "Limit the summary buffer to the predicated in the `display' group parameter."
+ (interactive)
+ (unless gnus-newsgroup-display
+ (error "There is no `display' group parameter"))
+ (let (articles)
+ (dolist (number gnus-newsgroup-articles)
+ (when (funcall gnus-newsgroup-display)
+ (push number articles)))
+ (gnus-summary-limit articles))
+ (gnus-summary-position-point))
+
(defalias 'gnus-summary-delete-marked-as-read 'gnus-summary-limit-to-unread)
(make-obsolete
'gnus-summary-delete-marked-as-read 'gnus-summary-limit-to-unread)
(gnus-summary-limit articles))
(gnus-summary-position-point)))
-(defun gnus-summary-limit-to-score (&optional score)
+(defun gnus-summary-limit-to-score (score)
"Limit to articles with score at or above SCORE."
- (interactive "P")
- (setq score (if score
- (prefix-numeric-value score)
- (or gnus-summary-default-score 0)))
+ (interactive "NLimit to articles with score of at least: ")
(let ((data gnus-newsgroup-data)
articles)
(while data
(gnus-id-to-thread (gnus-root-id id)))))
(prog1
(gnus-summary-limit (nconc articles gnus-newsgroup-limit))
- (gnus-summary-limit-include-matching-articles
- "subject"
- (regexp-quote (gnus-simplify-subject-re
- (mail-header-subject (gnus-id-to-header id)))))
+ (gnus-summary-limit-include-matching-articles
+ "subject"
+ (regexp-quote (gnus-simplify-subject-re
+ (mail-header-subject (gnus-id-to-header id)))))
(gnus-summary-position-point))))
(defun gnus-summary-limit-include-matching-articles (header regexp)
;; Most groups have nothing to remove.
(if (or gnus-inhibit-limiting
(and (null gnus-newsgroup-dormant)
+ (eq gnus-newsgroup-display 'gnus-not-ignore)
(not (eq gnus-fetch-old-headers 'some))
(not (numberp gnus-fetch-old-headers))
(not (eq gnus-fetch-old-headers 'invisible))
(push (cons number gnus-low-score-mark)
gnus-newsgroup-reads)))
t)
+ ;; Do the `display' group parameter.
+ (and gnus-newsgroup-display
+ (not (funcall gnus-newsgroup-display)))
;; Check NoCeM things.
(if (and gnus-use-nocem
(gnus-nocem-unwanted-article-p
(delete-matching-lines "^Path:\\|^From ")
(widen))
(unwind-protect
- (if (let ((gnus-newsgroup-ephemeral-charset gnus-newsgroup-charset)
+ (if (let ((gnus-newsgroup-ephemeral-charset gnus-newsgroup-charset)
(gnus-newsgroup-ephemeral-ignored-charsets
gnus-newsgroup-ignored-charsets))
(gnus-group-read-ephemeral-group
name `(nndoc ,name (nndoc-address ,(get-buffer dig))
(nndoc-article-type
,(if force 'mbox 'guess))) t))
- ;; Make all postings to this group go to the parent group.
- (nconc (gnus-info-params (gnus-get-info name))
- params)
- ;; Couldn't select this doc group.
- (switch-to-buffer buf)
- (gnus-set-global-variables)
- (gnus-configure-windows 'summary)
- (gnus-message 3 "Article couldn't be entered?"))
+ ;; Make all postings to this group go to the parent group.
+ (nconc (gnus-info-params (gnus-get-info name))
+ params)
+ ;; Couldn't select this doc group.
+ (switch-to-buffer buf)
+ (gnus-set-global-variables)
+ (gnus-configure-windows 'summary)
+ (gnus-message 3 "Article couldn't be entered?"))
(kill-buffer dig)))))
(defun gnus-summary-read-document (n)
(nndoc-article-type guess))
t nil t))
(progn
- ;; Make all postings to this group go to the parent group.
+ ;; Make all postings to this group go to the parent group.
(nconc (gnus-info-params (gnus-get-info egroup))
params)
(push egroup groups))
(nreverse articles)))
(defun gnus-summary-find-matching (header regexp &optional backward unread
- not-case-fold)
+ not-case-fold not-matching)
"Return a list of all articles that match REGEXP on HEADER.
The search stars on the current article and goes forwards unless
BACKWARD is non-nil. If BACKWARD is `all', do all articles.
If UNREAD is non-nil, only unread articles will
be taken into consideration. If NOT-CASE-FOLD, case won't be folded
-in the comparisons."
+in the comparisons. If NOT-MATCHING, return a list of all articles that
+not match REGEXP on HEADER."
(let ((case-fold-search (not not-case-fold))
articles d func)
(if (consp header)
(when (and (or (not unread) ; We want all articles...
(gnus-data-unread-p d)) ; Or just unreads.
(vectorp (gnus-data-header d)) ; It's not a pseudo.
- (string-match regexp
- (funcall func (gnus-data-header d)))) ; Match.
+ (if not-matching
+ (not (string-match
+ regexp
+ (funcall func (gnus-data-header d))))
+ (string-match regexp
+ (funcall func (gnus-data-header d)))))
(push (gnus-data-number d) articles))) ; Success!
(nreverse articles)))
(list (let ((completion-ignore-case t))
(completing-read
"Header name: "
- (mapcar (lambda (string) (list string))
- '("Number" "Subject" "From" "Lines" "Date"
- "Message-ID" "Xref" "References" "Body"))
+ (mapcar (lambda (header) (list (format "%s" header)))
+ (append
+ '("Number" "Subject" "From" "Lines" "Date"
+ "Message-ID" "Xref" "References" "Body")
+ gnus-extra-headers))
nil 'require-match))
(read-string "Regexp: ")
(read-key-sequence "Command: ")
(save-excursion
(save-window-excursion
(gnus-message 6 "Executing %s..." (key-description command))
- ;; We'd like to execute COMMAND interactively so as to give arguments.
+;; We'd like to execute COMMAND interactively so as to give arguments.
(gnus-execute header regexp
`(call-interactively ',(key-binding command))
backward)
(when gnus-page-broken
(gnus-narrow-to-page))))
+(defun gnus-summary-print-truncate-and-quote (string &optional len)
+ "Truncate to LEN and quote all \"(\"'s in STRING."
+ (gnus-replace-in-string (if (and len (> (length string) len))
+ (substring string 0 len)
+ string)
+ "[()]" "\\\\\\&"))
+
(defun gnus-summary-print-article (&optional filename n)
"Generate and print a PostScript image of the N next (mail) articles.
(dolist (article (gnus-summary-work-articles n))
(gnus-summary-select-article nil nil 'pseudo article)
(gnus-eval-in-buffer-window gnus-article-buffer
- (let ((buffer (generate-new-buffer " *print*")))
- (unwind-protect
- (progn
- (copy-to-buffer buffer (point-min) (point-max))
- (set-buffer buffer)
- (gnus-article-delete-invisible-text)
- (when (gnus-visual-p 'article-highlight 'highlight)
- ;; Copy-to-buffer doesn't copy overlay. So redo
- ;; highlight.
- (let ((gnus-article-buffer buffer))
- (gnus-article-highlight-citation t)
- (gnus-article-highlight-signature)))
- (let ((ps-left-header
- (list
- (concat "("
- (mail-header-subject gnus-current-headers) ")")
- (concat "("
- (mail-header-from gnus-current-headers) ")")))
- (ps-right-header
- (list
- "/pagenumberstring load"
- (concat "("
- (mail-header-date gnus-current-headers) ")"))))
- (gnus-run-hooks 'gnus-ps-print-hook)
- (save-excursion
- (if window-system
- (ps-spool-buffer-with-faces)
- (ps-spool-buffer)))))
- (kill-buffer buffer))))
+ (gnus-print-buffer))
(gnus-summary-remove-process-mark article))
(ps-despool filename))
+(defun gnus-print-buffer ()
+ (let ((buffer (generate-new-buffer " *print*")))
+ (unwind-protect
+ (progn
+ (copy-to-buffer buffer (point-min) (point-max))
+ (set-buffer buffer)
+ (gnus-article-delete-invisible-text)
+ (when (gnus-visual-p 'article-highlight 'highlight)
+ ;; Copy-to-buffer doesn't copy overlay. So redo
+ ;; highlight.
+ (let ((gnus-article-buffer buffer))
+ (gnus-article-highlight-citation t)
+ (gnus-article-highlight-signature)))
+ (let ((ps-left-header
+ (list
+ (concat "("
+ (gnus-summary-print-truncate-and-quote
+ (mail-header-subject gnus-current-headers)
+ 66) ")")
+ (concat "("
+ (gnus-summary-print-truncate-and-quote
+ (mail-header-from gnus-current-headers)
+ 45) ")")))
+ (ps-right-header
+ (list
+ "/pagenumberstring load"
+ (concat "("
+ (mail-header-date gnus-current-headers) ")"))))
+ (gnus-run-hooks 'gnus-ps-print-hook)
+ (save-excursion
+ (if window-system
+ (ps-spool-buffer-with-faces)
+ (ps-spool-buffer)))))
+ (kill-buffer buffer))))
+
(defun gnus-summary-show-article (&optional arg)
- "Force re-fetching of the current article.
+ "Force redisplaying of the current article.
If ARG (the prefix) is a number, show the article with the charset
defined in `gnus-summary-show-article-charset-alist', or the charset
-inputed.
+input.
If ARG (the prefix) is non-nil and not a number, show the raw article
-without any article massaging functions being run."
+without any article massaging functions being run. Normally, the key strokes
+are `C-u g'."
(interactive "P")
(cond
((numberp arg)
+ (gnus-summary-show-article t)
(let ((gnus-newsgroup-charset
(or (cdr (assq arg gnus-summary-show-article-charset-alist))
- (read-coding-system "Charset: ")))
+ (mm-read-coding-system
+ "View as charset: "
+ (save-excursion
+ (set-buffer gnus-article-buffer)
+ (let ((coding-systems
+ (detect-coding-region (point) (point-max))))
+ (or (car-safe coding-systems)
+ coding-systems))))))
(gnus-newsgroup-ignored-charsets 'gnus-all))
(gnus-summary-select-article nil 'force)
(let ((deps gnus-newsgroup-dependencies)
- head header)
+ head header lines)
(save-excursion
(set-buffer gnus-original-article-buffer)
(save-restriction
(message-narrow-to-head)
- (setq head (buffer-string)))
+ (setq head (buffer-string))
+ (goto-char (point-min))
+ (unless (re-search-forward "^lines:[ \t]\\([0-9]+\\)" nil t)
+ (goto-char (point-max))
+ (widen)
+ (setq lines (1- (count-lines (point) (point-max))))))
(with-temp-buffer
(insert (format "211 %d Article retrieved.\n"
(cdr gnus-article-current)))
(insert head)
+ (if lines (insert (format "Lines: %d\n" lines)))
(insert ".\n")
(let ((nntp-server-buffer (current-buffer)))
(setq header (car (gnus-get-newsgroup-headers deps t))))))
(gnus-data-find (cdr gnus-article-current))
header)
(gnus-summary-update-article-line
- (cdr gnus-article-current) header))))
+ (cdr gnus-article-current) header)
+ (when (gnus-summary-goto-subject (cdr gnus-article-current) nil t)
+ (gnus-summary-update-secondary-mark (cdr gnus-article-current))))))
((not arg)
;; Select the article the normal way.
(gnus-summary-select-article nil 'force))
(gnus-summary-goto-subject gnus-current-article)
(gnus-summary-position-point))
+(defun gnus-summary-show-raw-article ()
+ "Show the raw article without any article massaging functions being run."
+ (interactive)
+ (gnus-summary-show-article t))
+
(defun gnus-summary-verbose-headers (&optional arg)
"Toggle permanent full header display.
If ARG is a positive number, turn header display on.
(if hidden
(let ((gnus-treat-hide-headers nil)
(gnus-treat-hide-boring-headers nil))
- (setq gnus-article-wash-types
- (delq 'headers gnus-article-wash-types))
+ (gnus-delete-wash-type 'headers)
(gnus-treat-article 'head))
(gnus-treat-article 'head)))
(gnus-set-mode-line 'article)))))
(interactive "P")
(unless action
(setq action 'move))
- ;; Disable marking as read.
- (let (gnus-mark-article-hook)
- (save-window-excursion
- (gnus-summary-select-article)))
;; Check whether the source group supports the required functions.
(cond ((and (eq action 'move)
(not (gnus-check-backend-function
(error "The current group does not support article editing")))
(let ((articles (gnus-summary-work-articles n))
(prefix (if (gnus-check-backend-function
- 'request-move-article gnus-newsgroup-name)
+ 'request-move-article gnus-newsgroup-name)
(gnus-group-real-prefix gnus-newsgroup-name)
""))
(names '((move "Move" "Moving")
art-group to-method new-xref article to-groups)
(unless (assq action names)
(error "Unknown action %s" action))
+ ;; We have to select an article to give
+ ;; `gnus-read-move-group-name' an opportunity to suggest an
+ ;; appropriate default.
+ (unless (gnus-buffer-live-p gnus-original-article-buffer)
+ (gnus-summary-select-article nil nil nil (car articles)))
;; Read the newsgroup name.
(when (and (not to-newsgroup)
(not select-method))
(mail-header-xref (gnus-summary-article-header article))
" ")))
(setq new-xref (concat (gnus-group-real-name gnus-newsgroup-name)
- ":" article))
+ ":" (number-to-string article)))
(unless xref
(setq xref (list (system-name))))
(setq new-xref
(gnus-request-accept-article
to-newsgroup select-method (not articles))))
(setq new-xref (concat new-xref " " (car art-group)
- ":" (cdr art-group)))
+ ":"
+ (number-to-string (cdr art-group))))
;; Now we have the new Xrefs header, so we insert
;; it and replace the new article.
(nnheader-replace-header "Xref" new-xref)
(entry
(gnus-gethash pto-group gnus-newsrc-hashtb))
(info (nth 2 entry))
- (to-group (gnus-info-group info))
+ (to-group (gnus-info-group info))
to-marks)
;; Update the group that has been moved to.
(when (and info
(setcdr gnus-newsgroup-active to-article))
(while marks
- (when (memq article (symbol-value
- (intern (format "gnus-newsgroup-%s"
- (caar marks)))))
- (push (cdar marks) to-marks)
- ;; If the other group is the same as this group,
- ;; then we have to add the mark to the list.
- (when (equal to-group gnus-newsgroup-name)
- (set (intern (format "gnus-newsgroup-%s" (caar marks)))
- (cons to-article
- (symbol-value
- (intern (format "gnus-newsgroup-%s"
- (caar marks)))))))
- ;; Copy the marks to other group.
- (gnus-add-marked-articles
- to-group (cdar marks) (list to-article) info))
+ (when (eq (gnus-article-mark-to-type (cdar marks)) 'list)
+ (when (memq article (symbol-value
+ (intern (format "gnus-newsgroup-%s"
+ (caar marks)))))
+ (push (cdar marks) to-marks)
+ ;; If the other group is the same as this group,
+ ;; then we have to add the mark to the list.
+ (when (equal to-group gnus-newsgroup-name)
+ (set (intern (format "gnus-newsgroup-%s" (caar marks)))
+ (cons to-article
+ (symbol-value
+ (intern (format "gnus-newsgroup-%s"
+ (caar marks)))))))
+ ;; Copy the marks to other group.
+ (gnus-add-marked-articles
+ to-group (cdar marks) (list to-article) info)))
(setq marks (cdr marks)))
(gnus-request-set-mark to-group (list (list (list to-article)
- 'set
+ 'add
to-marks))))
(gnus-dribble-enter
(gnus-summary-mark-article article gnus-canceled-mark))))
(gnus-summary-remove-process-mark article))
;; Re-activate all groups that have been moved to.
- (while to-groups
- (save-excursion
- (set-buffer gnus-group-buffer)
- (when (gnus-group-goto-group (car to-groups) t)
- (gnus-group-get-new-news-this-group 1 t))
- (pop to-groups)))
+ (save-excursion
+ (set-buffer gnus-group-buffer)
+ (let ((gnus-group-marked to-groups))
+ (gnus-group-get-new-news-this-group nil t)))
(gnus-kill-buffer copy-buf)
(gnus-summary-position-point)
(gnus-summary-move-article n nil nil 'crosspost))
(defcustom gnus-summary-respool-default-method nil
- "Default method for respooling an article.
+ "Default method type for respooling an article.
If nil, use to the current newsgroup method."
- :type '(choice (gnus-select-method :value (nnml ""))
- (const nil))
+ :type 'symbol
:group 'gnus-summary-mail)
(defun gnus-summary-respool-article (&optional n method)
(erase-buffer)
(nnheader-insert-file-contents file)
(goto-char (point-min))
- (unless (nnheader-article-p)
- ;; This doesn't look like an article, so we fudge some headers.
+ (if (nnheader-article-p)
+ (save-restriction
+ (goto-char (point-min))
+ (search-forward "\n\n" nil t)
+ (narrow-to-region (point-min) (1- (point)))
+ (goto-char (point-min))
+ (unless (re-search-forward "^date:" nil t)
+ (goto-char (point-max))
+ (insert "Date: " (message-make-date (nth 5 atts)) "\n")))
+ ;; This doesn't look like an article, so we fudge some headers.
(setq atts (file-attributes file)
lines (count-lines (point-min) (point-max)))
(insert "From: " (read-string "From: ") "\n"
(setq gnus-newsgroup-expirable es))
;; We go through the old list of expirable, and mark all
;; really expired articles as nonexistent.
- (unless (eq es expirable) ;If nothing was expired, we don't mark.
+ (unless (eq es expirable) ;If nothing was expired, we don't mark.
(let ((gnus-use-cache nil))
(while expirable
(unless (memq (car expirable) es)
(with-current-buffer gnus-article-buffer
(prog1
gnus-article-mime-handles
- (setq gnus-article-mime-handles nil))))))
+ (setq gnus-article-mime-handles nil))))))
(t (setq force t)))
(if (and raw (not force) (equal gnus-newsgroup-name "nndraft:drafts"))
- (error "Can't edit the raw article in group nndraft:drafts."))
+ (error "Can't edit the raw article in group nndraft:drafts"))
(save-excursion
(set-buffer gnus-summary-buffer)
(let ((mail-parse-charset gnus-newsgroup-charset)
(let ((mbl mml-buffer-list))
(setq mml-buffer-list nil)
(mime-to-mml ,'current-handles)
- (make-local-hook 'kill-buffer-hook)
(let ((mbl1 mml-buffer-list))
(setq mml-buffer-list mbl)
(set (make-local-variable 'mml-buffer-list) mbl1))
+ (make-local-hook 'kill-buffer-hook)
(add-hook 'kill-buffer-hook 'mml-destroy-buffers t t))))
`(lambda (no-highlight)
(let ((mail-parse-charset ',gnus-newsgroup-charset)
"Make edits to the current article permanent."
(interactive)
(save-excursion
- ;; The buffer restriction contains the entire article if it exists.
+ ;; The buffer restriction contains the entire article if it exists.
(when (article-goto-body)
(let ((lines (count-lines (point) (point-max)))
(length (- (point-max) (point)))
(gnus-data-find (cdr gnus-article-current))
header)
(gnus-summary-update-article-line
- (cdr gnus-article-current) header))))))
+ (cdr gnus-article-current) header)
+ (if (gnus-summary-goto-subject
+ (cdr gnus-article-current) nil t)
+ (gnus-summary-update-secondary-mark
+ (cdr gnus-article-current))))))))
;; Update threads.
(set-buffer (or buffer gnus-summary-buffer))
- (gnus-summary-update-article (cdr gnus-article-current)))
+ (gnus-summary-update-article (cdr gnus-article-current))
+ (if (gnus-summary-goto-subject (cdr gnus-article-current) nil t)
+ (gnus-summary-update-secondary-mark
+ (cdr gnus-article-current))))
;; Prettify the article buffer again.
(unless no-highlight
(save-excursion
(execute-kbd-macro (concat (this-command-keys) key))
(gnus-article-edit-done))
+
+(defun gnus-summary-toggle-smiley (&optional arg)
+ "Toggle the display of smilies as small graphical icons."
+ (interactive "P")
+ (save-excursion
+ (set-buffer gnus-article-buffer)
+ (gnus-smiley-display arg)))
+
;;; Respooling
(defun gnus-summary-respool-query (&optional silent trace)
(while (and
(> n 0)
(if unmark
- (gnus-summary-remove-process-mark
- (gnus-summary-article-number))
+ (gnus-summary-remove-process-mark
+ (gnus-summary-article-number))
(gnus-summary-set-process-mark (gnus-summary-article-number)))
(zerop (gnus-summary-next-subject (if backward -1 1) nil t)))
(setq n (1- n)))
(error "No such mark type: %s" type)
(setq var (intern (format "gnus-newsgroup-%s" type)))
(set var (cons article (symbol-value var)))
- (if (memq type '(processable cached replied forwarded saved))
+ (if (memq type '(processable cached replied forwarded recent saved))
(gnus-summary-update-secondary-mark article)
- ;;; !!! This is bobus. We should find out what primary
+ ;;; !!! This is bogus. We should find out what primary
;;; !!! mark we want to set.
(gnus-summary-update-mark gnus-del-mark 'unread)))))
(setq mark gnus-del-mark))
(when (and (not no-expire)
gnus-newsgroup-auto-expire
- (memq mark gnus-auto-expirable-marks))
+ (memq mark gnus-auto-expirable-marks))
(setq mark gnus-expirable-mark))
(let ((article (or article (gnus-summary-article-number)))
(old-mark (gnus-summary-article-mark article)))
gnus-forwarded-mark)
((memq article gnus-newsgroup-saved)
gnus-saved-mark)
+ ((memq article gnus-newsgroup-recent)
+ gnus-recent-mark)
+ ((memq article gnus-newsgroup-unseen)
+ gnus-unseen-mark)
(t gnus-no-mark))
'replied)
(when (gnus-visual-p 'summary-highlight 'highlight)
(defun gnus-summary-update-mark (mark type)
(let ((forward (cdr (assq type gnus-summary-mark-positions)))
- (buffer-read-only nil))
+ (buffer-read-only nil))
(re-search-backward "[\n\r]" (gnus-point-at-bol) 'move-to-limit)
(when forward
(when (looking-at "\r")
(gnus-summary-mark-article gnus-current-article gnus-read-mark))))
(defun gnus-summary-mark-unread-as-ticked ()
- "Intended to be used by `gnus-summary-mark-article-hook'."
+ "Intended to be used by `gnus-summary-mark-article-hook'."
(when (memq gnus-current-article gnus-newsgroup-unreads)
(gnus-summary-mark-article gnus-current-article gnus-ticked-mark)))
(goto-char (point-min))
(push gnus-newsgroup-limit gnus-newsgroup-limits)
(setq gnus-newsgroup-limit (copy-sequence gnus-newsgroup-limit))
- (mapcar (lambda (x) (push (mail-header-number x)
+ (mapcar (lambda (x) (push (mail-header-number x)
gnus-newsgroup-limit))
headers)
(gnus-summary-prepare-unthreaded (nreverse headers))
(gnus-summary-position-point)
t))))
-(defun gnus-summary-catchup (&optional all quietly to-here not-mark)
+(defun gnus-summary-catchup (&optional all quietly to-here not-mark reverse)
"Mark all unread articles in this newsgroup as read.
If prefix argument ALL is non-nil, ticked and dormant articles will
also be marked as read.
If QUIETLY is non-nil, no questions will be asked.
If TO-HERE is non-nil, it should be a point in the buffer. All
-articles before this point will be marked as read.
+articles before (after, if REVERSE is set) this point will be marked as read.
Note that this function will only catch up the unread article
in the current summary buffer limitation.
The number of articles marked as read is returned."
;; We actually mark all articles as canceled, which we
;; have to do when using auto-expiry or adaptive scoring.
(gnus-summary-show-all-threads)
- (when (gnus-summary-first-subject (not all) t)
- (while (and
- (if to-here (< (point) to-here) t)
- (gnus-summary-mark-article-as-read gnus-catchup-mark)
- (gnus-summary-find-next (not all) nil nil t))))
+ (if (and to-here reverse)
+ (progn
+ (goto-char to-here)
+ (while (and
+ (gnus-summary-mark-article-as-read gnus-catchup-mark)
+ (gnus-summary-find-next (not all) nil nil t))))
+ (when (gnus-summary-first-subject (not all) t)
+ (while (and
+ (if to-here (< (point) to-here) t)
+ (gnus-summary-mark-article-as-read gnus-catchup-mark)
+ (gnus-summary-find-next (not all) nil nil t)))))
(gnus-set-mode-line 'summary))
t))
(gnus-summary-position-point)))
(gnus-summary-catchup all t beg)))))
(gnus-summary-position-point))
+(defun gnus-summary-catchup-from-here (&optional all)
+ "Mark all unticked articles after the current one as read.
+If ALL is non-nil, also mark ticked and dormant articles as read."
+ (interactive "P")
+ (save-excursion
+ (gnus-save-hidden-threads
+ (let ((beg (point)))
+ ;; We check that there are unread articles.
+ (when (or all (gnus-summary-find-next))
+ (gnus-summary-catchup all t beg nil t)))))
+
+ (gnus-summary-position-point))
(defun gnus-summary-catchup-all (&optional quietly)
"Mark all articles in this newsgroup as read."
(interactive "P")
(set-buffer gnus-summary-buffer)
(gnus-summary-unmark-all-processable)
(gnus-summary-update-article current-article)
+ (if (gnus-summary-goto-subject (cdr gnus-article-current) nil t)
+ (gnus-summary-update-secondary-mark (cdr gnus-article-current)))
(gnus-summary-rethread-current)
(gnus-message 3 "Article %d is now the child of article %d"
current-article parent-article)))))
(gnus-message 1 "Article %d is unsaveable" article))
;; This is a real article.
(save-window-excursion
- (gnus-summary-select-article t nil nil article))
+ (let ((gnus-display-mime-function nil)
+ (gnus-article-prepare-hook nil))
+ (gnus-summary-select-article t nil nil article)))
(save-excursion
(set-buffer save-buffer)
(erase-buffer)
(require 'gnus-art)
(let ((gnus-default-article-saver 'gnus-summary-save-in-pipe))
(gnus-summary-save-article arg t))
- (gnus-configure-windows 'pipe))
+ (let ((buffer (get-buffer "*Shell Command Output*")))
+ (if (and buffer
+ (with-current-buffer buffer (> (point-max) (point-min))))
+ (gnus-configure-windows 'pipe))))
(defun gnus-summary-save-article-mail (&optional arg)
"Append the current article to an mail file.
(let ((gnus-default-article-saver 'gnus-summary-save-body-in-file))
(gnus-summary-save-article arg)))
+(defun gnus-summary-muttprint (&optional arg)
+ "Print the current article using Muttprint.
+If N is a positive number, save the N next articles.
+If N is a negative number, save the N previous articles.
+If N is nil and any articles have been marked with the process mark,
+save those articles instead."
+ (interactive "P")
+ (require 'gnus-art)
+ (let ((gnus-default-article-saver 'gnus-summary-pipe-to-muttprint))
+ (gnus-summary-save-article arg t)))
+
(defun gnus-summary-pipe-message (program)
"Pipe the current article through PROGRAM."
(interactive "sProgram: ")
(let ((mail-header-separator ""))
(gnus-eval-in-buffer-window gnus-article-buffer
(save-restriction
- (widen)
- (let ((start (window-start))
- buffer-read-only)
- (message-pipe-buffer-body program)
- (set-window-start (get-buffer-window (current-buffer)) start))))))
+ (widen)
+ (let ((start (window-start))
+ buffer-read-only)
+ (message-pipe-buffer-body program)
+ (set-window-start (get-buffer-window (current-buffer)) start))))))
(defun gnus-get-split-value (methods)
"Return a value based on the split METHODS."
(nreverse split-name))
nil nil nil
'gnus-group-history))))
- (to-method (gnus-server-to-method (gnus-group-method to-newsgroup))))
+ (to-method (gnus-server-to-method (gnus-group-method to-newsgroup))))
(when to-newsgroup
(if (or (string= to-newsgroup "")
(string= to-newsgroup prefix))
(mark (or (gnus-summary-article-mark) gnus-unread-mark))
(inhibit-read-only t))
;; Eval the cars of the lists until we find a match.
- (let ((default gnus-summary-default-score))
+ (let ((default gnus-summary-default-score)
+ (default-high gnus-summary-default-high-score)
+ (default-low gnus-summary-default-low-score))
(while (and list
(not (eval (caar list))))
(setq list (cdr list))))
(gnus-set-difference articles
(mapcar (lambda (h) (mail-header-number h))
gnus-newsgroup-headers)))
- (setq gnus-newsgroup-headers
+ (setq gnus-newsgroup-headers
(merge 'list
gnus-newsgroup-headers
(gnus-fetch-headers articles)
;; Suppress duplicates?
(when gnus-suppress-duplicates
(gnus-dup-suppress-articles))
-
+
;; We might want to build some more threads first.
(when (and gnus-fetch-old-headers
(eq gnus-headers-retrieved-by 'nov))
(if (eq gnus-fetch-old-headers 'invisible)
- (gnus-build-all-threads)
+ (gnus-build-all-threads)
(gnus-build-old-threads)))
;; Let the Gnus agent mark articles as read.
(when gnus-agent
(or (memq i old) (push i older))
(incf i))
(setq len (length older))
- (cond
+ (cond
((null older) nil)
- ((numberp all)
+ ((numberp all)
(if (< all len)
(setq older (subseq older 0 all))))
(all nil)
(read-string
(format
"How many articles from %s (default %d): "
- (gnus-limit-string
+ (gnus-limit-string
(gnus-group-decoded-name gnus-newsgroup-name) 35)
len))))
- (unless (string-match "^[ \t]*$" input)
+ (unless (string-match "^[ \t]*$" input)
(setq all (string-to-number input))
(if (< all len)
(setq older (subseq older 0 all))))))))
(old-active gnus-newsgroup-active)
(nnmail-fetched-sources (list t))
i new)
- (setq gnus-newsgroup-active
+ (setq gnus-newsgroup-active
(gnus-activate-group gnus-newsgroup-name 'scan))
(setq i (1+ (cdr old-active)))
(while (<= i (cdr gnus-newsgroup-active))
(incf i))
(if (not new)
(message "No gnus is bad news.")
- (setq new (nreverse new))
+ (setq new (nreverse new))
(gnus-summary-insert-articles new)
(setq gnus-newsgroup-unreads
(append gnus-newsgroup-unreads new))
(mapcar 'list (gnus-topic-list))
nil t)))
(dolist (topic (gnus-current-topics topic))
+ (gnus-topic-goto-topic topic)
(gnus-topic-fold t))
(gnus-topic-goto-topic topic))
"Return entries for all visible groups in TOPIC.
If RECURSIVE is t, return groups in its subtopics too."
(let ((groups (cdr (assoc topic gnus-topic-alist)))
- info clevel unread group params visible-groups entry active)
+ info clevel unread group params visible-groups entry active)
(setq lowest (or lowest 1))
(setq level (or level gnus-level-unsubscribed))
;; We go through the newsrc to look for matches.
If LOWEST is non-nil, list all newsgroups of level LOWEST or higher."
(set-buffer gnus-group-buffer)
(let ((buffer-read-only nil)
- (lowest (or lowest 1))
+ (lowest (or lowest 1))
(not-in-list
(and gnus-group-listed-groups
(copy-sequence gnus-group-listed-groups))))
(when (and (eq major-mode 'gnus-group-mode)
gnus-topic-mode)
(let ((group (gnus-group-group-name))
- (m (point-marker))
+ (m (point-marker))
(buffer-read-only nil))
(when (and group
(gnus-get-info group)
"\r" gnus-topic-select-group
" " gnus-topic-read-group
"\C-c\C-x" gnus-topic-expire-articles
+ "c" gnus-topic-catchup-articles
"\C-k" gnus-topic-kill-group
"\C-y" gnus-topic-yank-group
"\M-g" gnus-topic-get-new-news-this-topic
"a" gnus-topic-sort-groups-by-alphabet
"u" gnus-topic-sort-groups-by-unread
"l" gnus-topic-sort-groups-by-level
+ "e" gnus-topic-sort-groups-by-server
"v" gnus-topic-sort-groups-by-score
"r" gnus-topic-sort-groups-by-rank
"m" gnus-topic-sort-groups-by-method))
(> (prefix-numeric-value arg) 0)))
;; Infest Gnus with topics.
(if (not gnus-topic-mode)
- (setq gnus-goto-missing-group-function nil)
+ (setq gnus-goto-missing-group-function nil)
(when (gnus-visual-p 'topic-menu 'menu)
(gnus-topic-make-menu-bar))
(gnus-set-format 'topic t)
(setq gnus-group-change-level-function 'gnus-topic-change-level)
(setq gnus-goto-missing-group-function 'gnus-topic-goto-missing-group)
(make-local-hook 'gnus-check-bogus-groups-hook)
- (add-hook 'gnus-check-bogus-groups-hook 'gnus-topic-clean-alist)
+ (add-hook 'gnus-check-bogus-groups-hook 'gnus-topic-clean-alist
+ nil 'local)
(setq gnus-topology-checked-p nil)
;; We check the topology.
(when gnus-newsrc-alist
(defun gnus-topic-select-group (&optional all)
"Select this newsgroup.
No article is selected automatically.
+If the group is opened, just switch the summary buffer.
If ALL is non-nil, already read articles become readable.
If ALL is a number, fetch this number of articles.
(gnus-group-expire-articles nil))
(gnus-message 5 "Expiring groups in %s...done" topic))))
+(defun gnus-topic-catchup-articles (topic)
+ "Catchup this topic or group.
+Also see `gnus-group-catchup'."
+ (interactive (list (gnus-group-topic-name)))
+ (if (not topic)
+ (call-interactively 'gnus-group-catchup-current)
+ (save-excursion
+ (let ((gnus-group-marked
+ (mapcar (lambda (entry) (car (nth 2 entry)))
+ (gnus-topic-find-groups topic gnus-level-killed t))))
+ (gnus-group-catchup-current)))))
+
(defun gnus-topic-read-group (&optional all no-article group)
"Read news in this newsgroup.
If the prefix argument ALL is non-nil, already read articles become
(interactive
(let ((topic (gnus-current-topic)))
(list topic
- (read-string (format "Rename %s to: " topic)))))
+ (read-string (format "Rename %s to: " topic) topic))))
;; Check whether the new name exists.
(when (gnus-topic-find-topology new-name)
(error "Topic '%s' already exists" new-name))
(interactive "P")
(gnus-topic-sort-groups 'gnus-group-sort-by-method reverse))
+(defun gnus-topic-sort-groups-by-server (&optional reverse)
+ "Sort the current topic alphabetically by server name.
+If REVERSE, sort in reverse order."
+ (interactive "P")
+ (gnus-topic-sort-groups 'gnus-group-sort-by-server reverse))
+
(defun gnus-topic-sort-topics-1 (top reverse)
(if (cdr top)
(let ((subtop
- (mapcar `(lambda (top)
- (gnus-topic-sort-topics-1 top ,reverse))
+ (mapcar (gnus-byte-compile
+ `(lambda (top)
+ (gnus-topic-sort-topics-1 top ,reverse)))
(sort (cdr top)
- '(lambda (t1 t2)
- (string-lessp (caar t1) (caar t2)))))))
+ (lambda (t1 t2)
+ (string-lessp (caar t1) (caar t2)))))))
(setcdr top (if reverse (reverse subtop) subtop))))
top)
(gnus-subscribe-alphabetically newsgroup)
;; Add the group to the topic.
(nconc (assoc topic gnus-topic-alist) (list newsgroup))
+ ;; if this topic specifies a default level, use it
+ (let ((subscribe-level (cdr (assq 'subscribe-level
+ (gnus-topic-parameters topic)))))
+ (when subscribe-level
+ (gnus-group-change-level newsgroup subscribe-level
+ gnus-level-default-subscribed)))
(throw 'end t)))
nil)))
(eval-and-compile
(autoload 'message-fetch-field "message")
+ (autoload 'gnus-get-buffer-window "gnus-win")
(autoload 'rmail-insert-rmail-file-header "rmail")
(autoload 'rmail-count-new-messages "rmail")
(autoload 'rmail-show-message "rmail"))
+(eval-and-compile
+ (cond
+ ((fboundp 'replace-in-string)
+ (defalias 'gnus-replace-in-string 'replace-in-string))
+ ((fboundp 'replace-regexp-in-string)
+ (defun gnus-replace-in-string (string regexp newtext &optional literal)
+ (replace-regexp-in-string regexp newtext string nil literal)))
+ (t
+ (defun gnus-replace-in-string (string regexp newtext &optional literal)
+ (let ((start 0) tail)
+ (while (string-match regexp string start)
+ (setq tail (- (length string) (match-end 0)))
+ (setq string (replace-match newtext nil literal string))
+ (setq start (- (length string) tail))))
+ string))))
+
(defun gnus-boundp (variable)
"Return non-nil if VARIABLE is bound and non-nil."
(and (boundp variable)
(defmacro gnus-eval-in-buffer-window (buffer &rest forms)
"Pop to BUFFER, evaluate FORMS, and then return to the original window."
(let ((tempvar (make-symbol "GnusStartBufferWindow"))
- (w (make-symbol "w"))
- (buf (make-symbol "buf")))
+ (w (make-symbol "w"))
+ (buf (make-symbol "buf")))
`(let* ((,tempvar (selected-window))
- (,buf ,buffer)
- (,w (get-buffer-window ,buf 'visible)))
+ (,buf ,buffer)
+ (,w (gnus-get-buffer-window ,buf 'visible)))
(unwind-protect
- (progn
- (if ,w
- (progn
- (select-window ,w)
- (set-buffer (window-buffer ,w)))
- (pop-to-buffer ,buf))
- ,@forms)
- (select-window ,tempvar)))))
+ (progn
+ (if ,w
+ (progn
+ (select-window ,w)
+ (set-buffer (window-buffer ,w)))
+ (pop-to-buffer ,buf))
+ ,@forms)
+ (select-window ,tempvar)))))
(put 'gnus-eval-in-buffer-window 'lisp-indent-function 1)
(put 'gnus-eval-in-buffer-window 'edebug-form-spec '(form body))
(defun gnus-goto-colon ()
(beginning-of-line)
- (search-forward ":" (gnus-point-at-eol) t))
+ (let ((eol (gnus-point-at-eol)))
+ (goto-char (or (text-property-any (point) eol 'gnus-position t)
+ (search-forward ":" eol t)
+ (point)))))
+
+(defun gnus-decode-newsgroups (newsgroups group &optional method)
+ (let ((method (or method (gnus-find-method-for-group group))))
+ (mapconcat (lambda (group)
+ (gnus-group-name-decode group (gnus-group-name-charset
+ method group)))
+ (message-tokenize-header newsgroups)
+ ",")))
(defun gnus-remove-text-with-property (prop)
"Delete all text in the current buffer with text property PROP."
(delete-char 1))
(goto-char (next-single-property-change (point) prop nil (point-max))))))
+(defun gnus-text-with-property (prop)
+ "Return a list of all points where the text has PROP."
+ (let ((points nil)
+ (point (point-min)))
+ (save-excursion
+ (while (< point (point-max))
+ (when (get-text-property point prop)
+ (push point points))
+ (incf point)))
+ (nreverse points)))
+
(require 'nnheader)
(defun gnus-newsgroup-directory-form (newsgroup)
"Make hierarchical directory name from NEWSGROUP name."
(yes-or-no-p prompt)
(message "")))
+;; By Frank Schmitt <ich@Frank-Schmitt.net>. Allows to have
+;; age-depending date representations. (e.g. just the time if it's
+;; from today, the day of the week if it's within the last 7 days and
+;; the full date if it's older)
+(defun gnus-seconds-today ()
+ "Returns the number of seconds passed today"
+ (let ((now (decode-time (current-time))))
+ (+ (car now) (* (car (cdr now)) 60) (* (car (nthcdr 2 now)) 3600))))
+
+(defun gnus-seconds-month ()
+ "Returns the number of seconds passed this month"
+ (let ((now (decode-time (current-time))))
+ (+ (car now) (* (car (cdr now)) 60) (* (car (nthcdr 2 now)) 3600)
+ (* (- (car (nthcdr 3 now)) 1) 3600 24))))
+
+(defun gnus-seconds-year ()
+ "Returns the number of seconds passed this year"
+ (let ((now (decode-time (current-time)))
+ (days (format-time-string "%j" (current-time))))
+ (+ (car now) (* (car (cdr now)) 60) (* (car (nthcdr 2 now)) 3600)
+ (* (- (string-to-number days) 1) 3600 24))))
+
+(defvar gnus-user-date-format-alist
+ '(((gnus-seconds-today) . "%k:%M")
+ (604800 . "%a %k:%M") ;;that's one week
+ ((gnus-seconds-month) . "%a %d")
+ ((gnus-seconds-year) . "%b %d")
+ (t . "%b %m '%y")) ;;this one is used when no other does match
+ "Alist of time in seconds and format specification used to display dates not older.
+The first element must be a number or a function returning a
+number. The second element is a format-specification as described in
+the documentation for format-time-string. The list must be ordered
+smallest number up. When there is an element, which is not a number,
+the corresponding format-specification will be used, disregarding any
+following elements. You can use the functions gnus-seconds-today,
+gnus-seconds-month, gnus-seconds-year which will return the number of
+seconds which passed today/this month/this year.")
+
+(defun gnus-user-date (messy-date)
+ "Format the messy-date acording to gnus-user-date-format-alist.
+Returns \" ? \" if there's bad input or if an other error occurs.
+Input should look like this: \"Sun, 14 Oct 2001 13:34:39 +0200\"."
+ (condition-case ()
+ (let* ((messy-date (safe-date-to-time messy-date))
+ (now (current-time))
+ ;;If we don't find something suitable we'll use this one
+ (my-format "%b %m '%y")
+ (high (lsh (- (car now) (car messy-date)) 16)))
+ (if (and (> high -1) (= (logand high 65535) 0))
+ ;;overflow and bad input
+ (let* ((difference (+ high (- (car (cdr now))
+ (car (cdr messy-date)))))
+ (templist gnus-user-date-format-alist)
+ (top (eval (caar templist))))
+ (while (if (numberp top) (< top difference) (not top))
+ (progn
+ (setq templist (cdr templist))
+ (setq top (eval (caar templist)))))
+ (if (stringp (cdr (car templist)))
+ (setq my-format (cdr (car templist))))))
+ (format-time-string (eval my-format) messy-date))
+ (error " ? ")))
+;;end of Frank's code
+
(defun gnus-dd-mmm (messy-date)
"Return a string like DD-MMM from a big messy string."
(condition-case ()
(defun gnus-mode-string-quote (string)
"Quote all \"%\"'s in STRING."
- (save-excursion
- (gnus-set-work-buffer)
- (insert string)
- (goto-char (point-min))
- (while (search-forward "%" nil t)
- (insert "%"))
- (buffer-string)))
+ (gnus-replace-in-string string "%" "%%"))
;; Make a hash table (default and minimum size is 256).
;; Optional argument HASHSIZE specifies the table size.
(setq ids (cdr ids)))
(car ids))))
-(defsubst gnus-buffer-live-p (buffer)
+(defun gnus-buffer-live-p (buffer)
"Say whether BUFFER is alive or not."
(and buffer
(get-buffer buffer)
(defun gnus-horizontal-recenter ()
"Recenter the current buffer horizontally."
(if (< (current-column) (/ (window-width) 2))
- (set-window-hscroll (get-buffer-window (current-buffer) t) 0)
+ (set-window-hscroll (gnus-get-buffer-window (current-buffer) t) 0)
(let* ((orig (point))
- (end (window-end (get-buffer-window (current-buffer) t)))
+ (end (window-end (gnus-get-buffer-window (current-buffer) t)))
(max 0))
(when end
;; Find the longest line currently displayed in the window.
;; Scroll horizontally to center (sort of) the point.
(if (> max (window-width))
(set-window-hscroll
- (get-buffer-window (current-buffer) t)
+ (gnus-get-buffer-window (current-buffer) t)
(min (- (current-column) (/ (window-width) 3))
(+ 2 (- max (window-width)))))
- (set-window-hscroll (get-buffer-window (current-buffer) t) 0))
+ (set-window-hscroll (gnus-get-buffer-window (current-buffer) t) 0))
max))))
(defun gnus-read-event-char ()
;; A list of functions.
((or (cdr funs)
(listp (car funs)))
- `(lambda (t1 t2)
- ,(gnus-make-sort-function-1 (reverse funs))))
+ (gnus-byte-compile
+ `(lambda (t1 t2)
+ ,(gnus-make-sort-function-1 (reverse funs)))))
;; A list containing just one function.
(t
(car funs))))
(setq beg (point)))
(gnus-put-text-property beg (point) prop val)))))
+(defsubst gnus-put-overlay-excluding-newlines (beg end prop val)
+ "The same as `put-text-property', but don't put this prop on any newlines in the region."
+ (save-match-data
+ (save-excursion
+ (save-restriction
+ (goto-char beg)
+ (while (re-search-forward gnus-emphasize-whitespace-regexp end 'move)
+ (gnus-overlay-put
+ (gnus-make-overlay beg (match-beginning 0))
+ prop val)
+ (setq beg (point)))
+ (gnus-overlay-put (gnus-make-overlay beg (point)) prop val)))))
+
(defun gnus-put-text-property-excluding-characters-with-faces (beg end
prop val)
"The same as `put-text-property', but don't put props on characters with the `gnus-face' property."
;; Decide whether to append to a file or to an Emacs buffer.
(let ((outbuf (get-file-buffer filename)))
(if (not outbuf)
- (mm-append-to-file (point-min) (point-max) filename)
+ (let ((file-name-coding-system nnmail-pathname-coding-system))
+ (mm-append-to-file (point-min) (point-max) filename))
;; File has been visited, in buffer OUTBUF.
(set-buffer outbuf)
(let ((buffer-read-only nil)
(when msg
(goto-char (point-min))
(widen)
- (search-backward "\n\^_")
- (narrow-to-region (point) (point-max))
- (rmail-count-new-messages t)
- (when (rmail-summary-exists)
+ (search-backward "\n\^_")
+ (narrow-to-region (point) (point-max))
+ (rmail-count-new-messages t)
+ (when (rmail-summary-exists)
(rmail-select-summary
(rmail-update-summary)))
(rmail-count-new-messages t)
(insert "\n"))
(insert "\n"))
(goto-char (point-max))
- (mm-append-to-file (point-min) (point-max) filename)))
+ (let ((file-name-coding-system nnmail-pathname-coding-system))
+ (mm-append-to-file (point-min) (point-max) filename))))
;; File has been visited, in buffer OUTBUF.
(set-buffer outbuf)
(let ((buffer-read-only nil))
Return the modified alist."
(let (entry)
(while (setq entry (assq key alist))
- (setq alist (delq entry alist)))
+ (setq alist (delq entry alist)))
alist)))
(defmacro gnus-pull (key alist &optional assoc-p)
(defun gnus-set-window-start (&optional point)
"Set the window start to POINT, or (point) if nil."
- (let ((win (get-buffer-window (current-buffer) t)))
+ (let ((win (gnus-get-buffer-window (current-buffer) t)))
(when win
(set-window-start win (or point (point))))))
(or (string-equal x y)
(string-equal (downcase x) (downcase y)))))
+(defcustom gnus-use-byte-compile t
+ "If non-nil, byte-compile crucial run-time codes."
+ :type 'boolean
+ :version "21.1"
+ :group 'gnus-various)
+
+(defun gnus-byte-compile (form)
+ "Byte-compile FORM if `gnus-use-byte-compile' is non-nil."
+ (if gnus-use-byte-compile
+ (progn
+ (require 'bytecomp)
+ (defalias 'gnus-byte-compile 'byte-compile)
+ (byte-compile form))
+ form))
+
+(defun gnus-remassoc (key alist)
+ "Delete by side effect any elements of LIST whose car is `equal' to KEY.
+The modified LIST is returned. If the first member
+of LIST has a car that is `equal' to KEY, there is no way to remove it
+by side effect; therefore, write `(setq foo (remassoc key foo))' to be
+sure of changing the value of `foo'."
+ (when alist
+ (if (equal key (caar alist))
+ (cdr alist)
+ (setcdr alist (gnus-remassoc key (cdr alist)))
+ alist)))
+
+(defun gnus-update-alist-soft (key value alist)
+ (if value
+ (cons (cons key value) (gnus-remassoc key alist))
+ (gnus-remassoc key alist)))
+
+(defun gnus-create-info-command (node)
+ "Create a command that will go to info NODE."
+ `(lambda ()
+ (interactive)
+ ,(concat "Enter the info system at node " node)
+ (Info-goto-node ,node)
+ (setq gnus-info-buffer (current-buffer))
+ (gnus-configure-windows 'info)))
+
+(defun gnus-not-ignore (&rest args)
+ t)
+
+(defvar gnus-directory-sep-char-regexp "/"
+ "The regexp of directory separator character.
+If you find some problem with the directory separator character, try
+\"[/\\\\\]\" for some systems.")
+
+(defun gnus-url-unhex (x)
+ (if (> x ?9)
+ (if (>= x ?a)
+ (+ 10 (- x ?a))
+ (+ 10 (- x ?A)))
+ (- x ?0)))
+
+(defun gnus-url-unhex-string (str &optional allow-newlines)
+ "Remove %XXX embedded spaces, etc in a url.
+If optional second argument ALLOW-NEWLINES is non-nil, then allow the
+decoding of carriage returns and line feeds in the string, which is normally
+forbidden in URL encoding."
+ (setq str (or (mm-subst-char-in-string ?+ ? str) ""))
+ (let ((tmp "")
+ (case-fold-search t))
+ (while (string-match "%[0-9a-f][0-9a-f]" str)
+ (let* ((start (match-beginning 0))
+ (ch1 (gnus-url-unhex (elt str (+ start 1))))
+ (code (+ (* 16 ch1)
+ (gnus-url-unhex (elt str (+ start 2))))))
+ (setq tmp (concat
+ tmp (substring str 0 start)
+ (cond
+ (allow-newlines
+ (char-to-string code))
+ ((or (= code ?\n) (= code ?\r))
+ " ")
+ (t (char-to-string code))))
+ str (substring str (match-end 0)))))
+ (setq tmp (concat tmp str))
+ tmp))
+
(provide 'gnus-util)
;;; gnus-util.el ends here
"Date: %s\nFrom: %s\nSubject: %s Digest\n\n"
(current-time-string) name name))
(when (and message-forward-as-mime gnus-uu-digest-buffer)
- ;; The default part in multipart/digest is message/rfc822.
- ;; Subject is a fake head.
(insert "<#part type=message/rfc822>\nSubject: Topics\n\n"))
(insert "Topics:\n")))
(when (not (eq in-state 'end))
;; The original article buffer is hosed, shoot it down.
(gnus-kill-buffer gnus-original-article-buffer)
-
+ (setq gnus-current-article nil)
result-files))
(defun gnus-uu-grab-view (file)
(let ((nnheader-file-name-translation-alist
'((?/ . ?,) (? . ?_) (?* . ?_) (?$ . ?_))))
(nnheader-translate-file-chars (match-string 1))))
- (replace-match (concat "begin 644 " gnus-uu-file-name) t t)
+ (replace-match (concat "begin 644 " gnus-uu-file-name) t t)
;; Remove any non gnus-uu-body-line right after start.
(forward-line 1)
(provide 'gnus-uu)
-;; gnus-uu.el ends here
+;;; gnus-uu.el ends here
;;; gnus-vm.el --- vm interface for Gnus
-;; Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000
+;; Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
;; Author: Per Persson <pp@gnu.ai.mit.edu>
(provide 'gnus-vm)
-;;; gnus-vm.el ends here.
+;;; gnus-vm.el ends here
(eval-when-compile (require 'cl))
(require 'gnus)
+(require 'gnus-util)
(defgroup gnus-windows nil
"Window configuration."
:group 'gnus-windows
:type 'boolean)
+(defcustom gnus-use-frames-on-any-display nil
+ "*If non-nil, frames on all displays will be considered useable by Gnus.
+When nil, only frames on the same display as the selected frame will be
+used to display Gnus windows."
+ :group 'gnus-windows
+ :type 'boolean)
+
(defvar gnus-buffer-configuration
'((group
(vertical 1.0
(if gnus-carpal '(summary-carpal 4))))
(article
(cond
- ((and gnus-use-picons
- (eq gnus-picons-display-where 'picons))
- '(frame 1.0
- (vertical 1.0
- (summary 0.25 point)
- (if gnus-carpal '(summary-carpal 4))
- (article 1.0))
- (vertical ((height . 5) (width . 15)
- (user-position . t)
- (left . -1) (top . 1))
- (picons 1.0))))
(gnus-use-trees
'(vertical 1.0
(summary 0.25 point)
("*Shell Command Output*" 1.0)))
(bug
(vertical 1.0
- ("*Gnus Help Bug*" 0.5)
+ (if gnus-bug-create-help-buffer '("*Gnus Help Bug*" 0.5))
("*Gnus Bug*" 1.0 point)))
(score-trace
(vertical 1.0
(compose-bounce
(vertical 1.0
(article 0.5)
- (message 1.0 point))))
+ (message 1.0 point)))
+ (display-term
+ (vertical 1.0
+ ("*display*" 1.0))))
"Window configuration for all possible Gnus buffers.
See the Gnus manual for an explanation of the syntax used.")
(mail . gnus-message-buffer)
(post-news . gnus-message-buffer)
(faq . gnus-faq-buffer)
- (picons . gnus-picons-buffer-name)
(tree . gnus-tree-buffer)
(score-trace . "*Score Trace*")
(split-trace . "*Split Trace*")
(draft . gnus-draft-buffer))
"Mapping from short symbols to buffer names or buffer variables.")
+(defcustom gnus-configure-windows-hook nil
+ "*A hook called when configuring windows."
+ :group 'gnus-windowns
+ :type 'hook)
+
;;; Internal variables.
(defvar gnus-current-window-configuration nil
;; put point in the assigned buffer, and do not touch the
;; winconf.
(select-window all-visible)
-
+
;; Make sure "the other" buffer, nntp-server-buffer, is live.
(unless (gnus-buffer-live-p nntp-server-buffer)
(nnheader-init-server-buffer))
;; This is not a `frame' split, so we ignore the
;; other frames.
(delete-other-windows)
- ;; This is a `frame' split, so we delete all windows
+ ;; This is a `frame' split, so we delete all windows
;; on all frames.
(gnus-delete-windows-in-gnusey-frames))
;; Just remove some windows.
(switch-to-buffer nntp-server-buffer)
(set-buffer nntp-server-buffer))
(gnus-configure-frame split)
+ (run-hooks 'gnus-configure-windows-hook)
(when gnus-window-frame-focus
(select-frame (window-frame gnus-window-frame-focus))))))))
(unless buffer
(error "Invalid buffer type: %s" type))
(if (and (setq buf (get-buffer (gnus-window-to-buffer-helper buffer)))
- (setq win (get-buffer-window buf t)))
+ (setq win (gnus-get-buffer-window buf t)))
(if (memq 'point split)
(setq all-visible win))
(setq all-visible nil)))
(mapcar (lambda (b) (delete-windows-on b t))
(delq lowest-buf bufs)))))
+(eval-and-compile
+ (cond
+ ((fboundp 'frames-on-display-list)
+ (defalias 'gnus-frames-on-display-list 'frames-on-display-list))
+ ((and (featurep 'xemacs) (fboundp 'frame-device))
+ (defun gnus-frames-on-display-list ()
+ (apply 'filtered-frame-list 'identity (list (frame-device nil)))))
+ (t
+ (defalias 'gnus-frames-on-display-list 'frame-list))))
+
+(defun gnus-get-buffer-window (buffer &optional frame)
+ (cond ((and (null gnus-use-frames-on-any-display)
+ (memq frame '(t 0 visible)))
+ (car
+ (let ((frames (gnus-frames-on-display-list)))
+ (gnus-delete-if (lambda (win) (not (memq (window-frame win)
+ frames)))
+ (get-buffer-window-list buffer nil frame)))))
+ (t
+ (get-buffer-window buffer frame))))
+
(provide 'gnus-win)
;;; gnus-win.el ends here
(error "Can't find glyph directory. \
Possibly the `etc' directory has not been installed.")))
-;;(format "%02x%02x%02x" 114 66 20) "724214"
-
-(defvar gnus-xmas-logo-color-alist
- '((flame "#cc3300" "#ff2200")
- (pine "#c0cc93" "#f8ffb8")
- (moss "#a1cc93" "#d2ffb8")
- (irish "#04cc90" "#05ff97")
- (sky "#049acc" "#05deff")
- (tin "#6886cc" "#82b6ff")
- (velvet "#7c68cc" "#8c82ff")
- (grape "#b264cc" "#cf7df")
- (labia "#cc64c2" "#fd7dff")
- (berry "#cc6485" "#ff7db5")
- (dino "#724214" "#1e3f03")
- (neutral "#b4b4b4" "#878787")
- (september "#bf9900" "#ffcc00"))
- "Color alist used for the Gnus logo.")
-
-(defcustom gnus-xmas-logo-color-style 'dino
- "*Color styles used for the Gnus logo."
- :type '(choice (const flame) (const pine) (const moss)
- (const irish) (const sky) (const tin)
- (const velvet) (const grape) (const labia)
- (const berry) (const neutral) (const september)
- (const dino))
- :group 'gnus-xmas)
-
-(defvar gnus-xmas-logo-colors
- (cdr (assq gnus-xmas-logo-color-style gnus-xmas-logo-color-alist))
- "Colors used for the Gnus logo.")
-
-(defcustom gnus-article-x-face-command
- (if (or (featurep 'xface)
- (featurep 'xpm))
- 'gnus-xmas-article-display-xface
- "{ echo '/* Width=48, Height=48 */'; uncompface; } | icontopbm | ee -")
- "*String or function to be executed to display an X-Face header.
-If it is a string, the command will be executed in a sub-shell
-asynchronously. The compressed face will be piped to this command."
- :type '(choice string function))
-
;;; Internal variables.
;; Don't warn about these undefined variables.
(if (stringp buffer)
nil
(map-extents (lambda (extent ignored)
- (remove-text-properties
- start end
- (list (extent-property extent 'text-prop) nil)
- buffer)
+ (remove-text-properties
+ start end
+ (list (extent-property extent 'text-prop) nil)
+ buffer)
nil)
- buffer start end nil nil 'text-prop)
+ buffer start end nil nil 'text-prop)
(gnus-add-text-properties start end props buffer)))
(defun gnus-xmas-highlight-selected-summary ()
(defun gnus-xmas-appt-select-lowest-window ()
(let* ((lowest-window (selected-window))
(bottom-edge (car (cdr (cdr (cdr (window-pixel-edges))))))
- (last-window (previous-window))
- (window-search t))
+ (last-window (previous-window))
+ (window-search t))
(while window-search
(let* ((this-window (next-window))
- (next-bottom-edge (car (cdr (cdr (cdr
- (window-pixel-edges
+ (next-bottom-edge (car (cdr (cdr (cdr
+ (window-pixel-edges
this-window)))))))
- (when (< bottom-edge next-bottom-edge)
+ (when (< bottom-edge next-bottom-edge)
(setq bottom-edge next-bottom-edge)
(setq lowest-window this-window))
- (select-window this-window)
- (when (eq last-window this-window)
+ (select-window this-window)
+ (when (eq last-window this-window)
(select-window lowest-window)
(setq window-search nil))))))
(defalias 'gnus-put-text-property 'gnus-xmas-put-text-property)
(defalias 'gnus-deactivate-mark 'ignore)
(defalias 'gnus-window-edges 'window-pixel-edges)
-
+
(if (and (<= emacs-major-version 19)
(< emacs-minor-version 14))
(defalias 'gnus-set-text-properties 'gnus-xmas-set-text-properties))
(defalias 'gnus-region-active-p 'region-active-p)
(defalias 'gnus-annotation-in-region-p 'gnus-xmas-annotation-in-region-p)
(defalias 'gnus-mime-button-menu 'gnus-xmas-mime-button-menu)
+ (defalias 'gnus-image-type-available-p 'gnus-xmas-image-type-available-p)
+ (defalias 'gnus-put-image 'gnus-xmas-put-image)
+ (defalias 'gnus-create-image 'gnus-xmas-create-image)
+ (defalias 'gnus-remove-image 'gnus-xmas-remove-image)
;; These ones are not defcutom'ed, sometimes not even defvar'ed. They
;; probably should. If that is done, the code below should then be moved
`[xpm
:file ,logo-xpm
:color-symbols
- (("thing" . ,(car gnus-xmas-logo-colors))
- ("shadow" . ,(cadr gnus-xmas-logo-colors))
+ (("thing" . ,(car gnus-logo-colors))
+ ("shadow" . ,(cadr gnus-logo-colors))
("background" . ,(face-background 'default)))])
((featurep 'xbm)
`[xbm :file ,logo-xbm])
(cons (current-buffer) bar)))))
(defun gnus-xmas-mail-strip-quoted-names (address)
- "Protect mail-strip-quoted-names from NIL input.
+ "Protect mail-strip-quoted-names from nil input.
XEmacs compatibility workaround."
(if (null address)
nil
"Face to show X face"
:group 'gnus-xmas)
-(defun gnus-xmas-article-display-xface (beg end &optional buffer)
- "Display any XFace headers in BUFFER."
+(defun gnus-xmas-article-display-xface (data)
+ "Display the XFace in DATA."
(save-excursion
(let ((xface-glyph
(cond
((featurep 'xface)
(make-glyph (vector 'xface :data
- (concat "X-Face: "
- (if buffer
- (with-current-buffer buffer
- (buffer-substring beg end))
- (buffer-substring beg end))))))
+ (concat "X-Face: " data))))
((featurep 'xpm)
- (let ((cur (or buffer (current-buffer))))
+ (let ((cur (current-buffer)))
(save-excursion
(gnus-set-work-buffer)
- (insert-buffer-substring cur beg end)
+ (insert data)
(let ((coding-system-for-read 'binary)
(coding-system-for-write 'binary))
(gnus-xmas-call-region "uncompface")
(make-glyph
(vector 'xpm :data (buffer-string)))))))
(t
- (make-glyph [nothing]))))
- (ext (make-extent (progn
- (goto-char (point-min))
- (re-search-forward "^From:" nil t)
- (point))
- (1+ (point)))))
- (set-glyph-face xface-glyph 'gnus-x-face)
- (set-extent-begin-glyph ext xface-glyph)
- (set-extent-property ext 'duplicable t))))
+ (make-glyph [nothing])))))
+ ;;(set-glyph-face xface-glyph 'gnus-x-face)
+
+ (gnus-article-goto-header "from")
+ (gnus-put-image xface-glyph " ")
+ (gnus-add-wash-type 'xface)
+ (gnus-add-image 'xface xface-glyph))))
(defvar gnus-xmas-modeline-left-extent
(let ((ext (copy-extent modeline-buffer-id-left-extent)))
(gnus-xmas-menu-add mailing-list
gnus-mailing-list-menu))
+(defun gnus-xmas-image-type-available-p (type)
+ (featurep type))
+
+(defun gnus-xmas-create-image (file)
+ (with-temp-buffer
+ (insert-file-contents file)
+ (mm-create-image-xemacs (car (last (split-string file "[.]"))))))
+
+(defun gnus-xmas-put-image (glyph &optional string)
+ (let ((begin (point))
+ extent)
+ (insert string)
+ (setq extent (make-extent begin (point)))
+ (set-extent-property extent 'gnus-image t)
+ (set-extent-property extent 'duplicable t)
+ (set-extent-property extent 'begin-glyph glyph)))
+
+(defun gnus-xmas-remove-image (image)
+ (map-extents
+ (lambda (ext unused)
+ (when (equal (extent-begin-glyph ext) image)
+ (set-extent-property ext 'begin-glyph nil))
+ nil)
+ nil nil nil nil nil 'gnus-image))
+
(provide 'gnus-xmas)
;;; gnus-xmas.el ends here
;;; gnus.el --- a newsreader for GNU Emacs
-;; Copyright (C) 1987, 1988, 1989, 1990, 1993, 1994, 1995, 1996,
-;; 1997, 1998, 2000, 2001 Free Software Foundation, Inc.
+;; Copyright (C) 1987, 1988, 1989, 1990, 1993, 1994, 1995, 1996,
+;; 1997, 1998, 2000, 2001, 2002 Free Software Foundation, Inc.
;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
;; Lars Magne Ingebrigtsen <larsi@gnus.org>
(eval '(run-hooks 'gnus-load-hook))
(eval-when-compile (require 'cl))
+(require 'wid-edit)
(require 'mm-util)
(defgroup gnus nil
:group 'news
:group 'mail)
+(defgroup gnus-format nil
+ "Dealing with formatting issues."
+ :group 'news
+ :group 'mail)
+
(defgroup gnus-charset nil
"Group character set issues."
:link '(custom-manual "(gnus)Charsets")
"Options related to newsservers and other servers used by Gnus."
:group 'gnus)
+(defgroup gnus-server-visual nil
+ "Highlighting and menus in the server buffer."
+ :group 'gnus-visual
+ :group 'gnus-server)
+
(defgroup gnus-message '((message custom-group))
"Composing replies and followups in Gnus."
:group 'gnus)
:link '(custom-manual "(gnus)Exiting Gnus")
:group 'gnus)
-(defconst gnus-version-number "0.03"
+(defconst gnus-version-number "0.04"
"Version number for this version of Gnus.")
(defconst gnus-version (format "Oort Gnus v%s" gnus-version-number)
(defface gnus-splash-face
'((((class color)
(background dark))
- (:foreground "Brown"))
+ (:foreground "#888888"))
(((class color)
(background light))
- (:foreground "Brown"))
+ (:foreground "#888888"))
(t
()))
- "Face of the splash screen.")
+ "Face for the splash screen.")
(defun gnus-splash ()
(save-excursion
(defvar gnus-simple-splash nil)
+;;(format "%02x%02x%02x" 114 66 20) "724214"
+
+(defvar gnus-logo-color-alist
+ '((flame "#cc3300" "#ff2200")
+ (pine "#c0cc93" "#f8ffb8")
+ (moss "#a1cc93" "#d2ffb8")
+ (irish "#04cc90" "#05ff97")
+ (sky "#049acc" "#05deff")
+ (tin "#6886cc" "#82b6ff")
+ (velvet "#7c68cc" "#8c82ff")
+ (grape "#b264cc" "#cf7df")
+ (labia "#cc64c2" "#fd7dff")
+ (berry "#cc6485" "#ff7db5")
+ (dino "#724214" "#1e3f03")
+ (oort "#cccccc" "#888888")
+ (neutral "#b4b4b4" "#878787")
+ (september "#bf9900" "#ffcc00"))
+ "Color alist used for the Gnus logo.")
+
+(defcustom gnus-logo-color-style 'oort
+ "*Color styles used for the Gnus logo."
+ :type '(choice (const flame) (const pine) (const moss)
+ (const irish) (const sky) (const tin)
+ (const velvet) (const grape) (const labia)
+ (const berry) (const neutral) (const september)
+ (const dino))
+ :group 'gnus-xmas)
+
+(defvar gnus-logo-colors
+ (cdr (assq gnus-logo-color-style gnus-logo-color-alist))
+ "Colors used for the Gnus logo.")
+
(defun gnus-group-startup-message (&optional x y)
"Insert startup message in current buffer."
;; Insert the message.
(fboundp 'find-image)
(display-graphic-p)
(let ((image (find-image
- `((:type xpm :file "gnus.xpm")
+ `((:type xpm :file "gnus.xpm"
+ :color-symbols
+ (("thing" . ,(car gnus-logo-colors))
+ ("shadow" . ,(cadr gnus-logo-colors))
+ ("background" . ,(face-background 'default))))
(:type pbm :file "gnus.pbm"
;; Account for the pbm's blackground.
:background ,(face-foreground 'gnus-splash-face)
(require 'gnus-util)
(require 'nnheader)
-(defvar gnus-parameters nil
+(defcustom gnus-parameters nil
"Alist of group parameters.
For example:
((\"mail\\\\..*\" (gnus-show-threads nil)
- (gnus-use-scoring nil)
- (gnus-summary-line-format
- \"%U%R%z%I%(%[%d:%ub%-20,20f%]%) %s\\n\")
- (gcc-self . t)
- (display . all))
+ (gnus-use-scoring nil)
+ (gnus-summary-line-format
+ \"%U%R%z%I%(%[%d:%ub%-23,23f%]%) %s\\n\")
+ (gcc-self . t)
+ (display . all))
(\"mail\\\\.me\" (gnus-use-scoring t))
(\"list\\\\..*\" (total-expire . t)
- (broken-reply-to . t)))")
+ (broken-reply-to . t)))"
+ :group 'gnus-group-various
+ :type '(repeat (cons regexp
+ (repeat sexp))))
(defvar gnus-group-parameters-more nil)
REST is a plist of following:
:type One of `bool', `list' or `nil'.
:function The name of the function.
-:function-document The document of the function.
+:function-document The documentation of the function.
:parameter-type The type for customizing the parameter.
-:parameter-document The document for the parameter.
+:parameter-document The documentation for the parameter.
:variable The name of the variable.
-:variable-document The document for the variable.
+:variable-document The documentation for the variable.
:variable-group The group for customizing the variable.
:variable-type The type for customizing the variable.
:variable-default The default value of the variable."
(variable-document (or (plist-get rest :variable-document) ""))
(variable-group (plist-get rest :variable-group))
(variable-type (or (plist-get rest :variable-type)
- `(quote (repeat (list (regexp :tag "Group")
- ,parameter-type)))))
+ `(quote (repeat
+ (list (regexp :tag "Group")
+ ,(car (cdr parameter-type)))))))
(variable-default (plist-get rest :variable-default)))
(list
'progn
:group 'gnus-server
:type 'gnus-select-method)
-(defcustom gnus-message-archive-method
- (progn
- ;; Don't require it at top level to avoid circularity.
- (require 'message)
- `(nnfolder
- "archive"
- (nnfolder-directory ,(nnheader-concat message-directory "archive"))
- (nnfolder-active-file
- ,(nnheader-concat message-directory "archive/active"))
- (nnfolder-get-new-mail nil)
- (nnfolder-inhibit-expiry t)))
+(defcustom gnus-message-archive-method "archive"
"*Method used for archiving messages you've sent.
-This should be a mail method.
-
-It's probably not very effective to change this variable once you've
-run Gnus once. After doing that, you must edit this server from the
-server buffer."
+This should be a mail method."
:group 'gnus-server
:group 'gnus-message
:type 'gnus-select-method)
write in another group, you could say something like:
\(setq gnus-message-archive-group
- '((if (message-news-p)
- \"misc-news\"
- \"misc-mail\")))
+ '((if (message-news-p)
+ \"misc-news\"
+ \"misc-mail\")))
Normally the group names returned by this variable should be
unprefixed -- which implicitly means \"store on the archive server\".
(defcustom gnus-local-domain nil
"Local domain name without a host name.
The DOMAINNAME environment variable is used instead if it is defined.
-If the `system-name' function returns the full Internet name, there is
+If the function `system-name' returns the full Internet name, there is
no need to set this variable."
:group 'gnus-message
:type '(choice (const :tag "default" nil)
(defcustom gnus-group-faq-directory
'("/ftp@mirrors.aol.com:/pub/rtfm/usenet/"
- "/ftp@sunsite.auc.dk:/pub/usenet/"
"/ftp@sunsite.doc.ic.ac.uk:/pub/usenet/news-faqs/"
"/ftp@src.doc.ic.ac.uk:/usenet/news-FAQS/"
"/ftp@ftp.seas.gwu.edu:/pub/rtfm/"
+ "/ftp@ftp.pasteur.fr:/pub/FAQ/"
"/ftp@rtfm.mit.edu:/pub/usenet/"
"/ftp@ftp.uni-paderborn.de:/pub/FAQ/"
"/ftp@ftp.sunet.se:/pub/usenet/"
ftp.seas.gwu.edu /pub/rtfm
rtfm.mit.edu /pub/usenet
Europe: ftp.uni-paderborn.de /pub/FAQ
- src.doc.ic.ac.uk /usenet/news-FAQS
+ src.doc.ic.ac.uk /usenet/news-FAQS
ftp.sunet.se /pub/usenet
- sunsite.auc.dk /pub/usenet
+ ftp.pasteur.fr /pub/FAQ
Asia: nctuccca.edu.tw /USENET/FAQ
hwarang.postech.ac.kr /pub/usenet
ftp.hk.super.net /mirror/faqs"
(defcustom gnus-large-newsgroup 200
"*The number of articles which indicates a large newsgroup.
If the number of articles in a newsgroup is greater than this value,
-confirmation is required for selecting the newsgroup."
+confirmation is required for selecting the newsgroup.
+If it is `nil', no confirmation is required."
:group 'gnus-group-select
:type 'integer)
:group 'gnus-meta
:type 'boolean)
-(defcustom gnus-use-picons nil
- "*If non-nil, display picons in a frame of their own."
- :group 'gnus-meta
- :type 'boolean)
-
(defcustom gnus-summary-prepare-exit-hook
'(gnus-summary-expire-articles)
"*A hook called when preparing to exit from the summary buffer.
("nnspool" post address)
("nnvirtual" post-mail virtual prompt-address)
("nnmbox" mail respool address)
- ("nnml" mail respool address)
+ ("nnml" post-mail respool address)
("nnmh" mail respool address)
("nndir" post-mail prompt-address physical-address)
("nneething" none address prompt-address physical-address)
("nnwarchive" none)
("nnlistserv" none)
("nnagent" post-mail)
- ("nnimap" post-mail address prompt-address physical-address))
+ ("nnimap" post-mail address prompt-address physical-address)
+ ("nnmaildir" mail respool address))
"*An alist of valid select methods.
The first element of each list lists should be a string with the name
of the select method. The other elements may be the category of
:type '(choice (const nil)
integer))
+;; There should be special validation for this.
+(define-widget 'gnus-email-address 'string
+ "An email address")
+
(gnus-define-group-parameter
to-address
:function-document
"Return GROUP's to-address."
:variable-document
- "*Alist of group regexps and correspondent to-addresses."
- :parameter-type '(gnus-email-address :tag "To Address")
- :parameter-document "\
+ "*Alist of group regexps and correspondent to-addresses."
+ :parameter-type '(gnus-email-address :tag "To Address")
+ :parameter-document "\
This will be used when doing followups and posts.
This is primarily useful in mail groups that represent closed
:variable gnus-auto-expirable-newsgroups
:variable-default nil
:variable-document
- "*Groups in which to automatically mark read articles as expirable.
+ "*Groups in which to automatically mark read articles as expirable.
If non-nil, this should be a regexp that should match all groups in
which to perform auto-expiry. This only makes sense for mail groups."
- :variable-group nnmail-expire
- :variable-type '(choice (const nil)
- regexp)
- :parameter-type '(const :tag "Automatic Expire" t)
- :parameter-document
- "All articles that are read will be marked as expirable.")
+ :variable-group nnmail-expire
+ :variable-type '(choice (const nil)
+ regexp)
+ :parameter-type '(const :tag "Automatic Expire" t)
+ :parameter-document
+ "All articles that are read will be marked as expirable.")
(gnus-define-group-parameter
total-expire
expiring - which means that all read articles will be deleted after
\(say) one week. (This only goes for mail groups and the like, of
course.)"
- :variable-group nnmail-expire
- :variable-type '(choice (const nil)
- regexp)
- :parameter-type '(const :tag "Total Expire" t)
- :parameter-document
- "All read articles will be put through the expiry process
+ :variable-group nnmail-expire
+ :variable-type '(choice (const nil)
+ regexp)
+ :parameter-type '(const :tag "Total Expire" t)
+ :parameter-document
+ "All read articles will be put through the expiry process
This happens even if they are not marked as expirable.
Use with caution.")
:function-document
"Return the default charset of GROUP."
:variable gnus-group-charset-alist
- :variable-default
+ :variable-default
'(("\\(^\\|:\\)hk\\>\\|\\(^\\|:\\)tw\\>\\|\\<big5\\>" cn-big5)
("\\(^\\|:\\)cn\\>\\|\\<chinese\\>" cn-gb-2312)
("\\(^\\|:\\)fj\\>\\|\\(^\\|:\\)japan\\>" iso-2022-jp-2)
("\\(^\\|:\\)\\(comp\\|rec\\|alt\\|sci\\|soc\\|news\\|gnu\\|bofh\\)\\>" iso-8859-1)
(".*" iso-8859-1))
:variable-document
- "Alist of regexps (to match group names) and default charsets to be used when reading."
- :variable-group gnus-charset
- :variable-type '(repeat (list (regexp :tag "Group")
- (symbol :tag "Charset")))
- :parameter-type '(symbol :tag "Charset")
- :parameter-document "\
+ "Alist of regexps (to match group names) and default charsets to be used when reading."
+ :variable-group gnus-charset
+ :variable-type '(repeat (list (regexp :tag "Group")
+ (symbol :tag "Charset")))
+ :parameter-type '(symbol :tag "Charset")
+ :parameter-document "\
The default charset to use in the group.")
+(gnus-define-group-parameter
+ post-method
+ :type list
+ :function-document
+ "Return a posting method for GROUP."
+ :variable gnus-post-method-alist
+ :variable-document
+ "Alist of regexps (to match group names) and method to be used when
+posting an article."
+ :variable-group gnus-group-foreign
+ :parameter-type
+ '(choice :tag "Posting Method"
+ (const :tag "Use native server" native)
+ (const :tag "Use current server" current)
+ (list :convert-widget
+ (lambda (widget)
+ (list 'sexp :tag "Methods"
+ :value gnus-select-method))))
+ :parameter-document
+ "Posting method for this group.")
+
(defcustom gnus-group-uncollapsed-levels 1
"Number of group name elements to leave alone when making a short group name."
:group 'gnus-group-visual
(const pick-menu)
(const grouplens-menu)))
+;; Byte-compiler warning.
+(defvar gnus-visual)
+;; Find out whether the gnus-visual TYPE is wanted.
+(defun gnus-visual-p (&optional type class)
+ (and gnus-visual ; Has to be non-nil, at least.
+ (if (not type) ; We don't care about type.
+ gnus-visual
+ (if (listp gnus-visual) ; It's a list, so we check it.
+ (or (memq type gnus-visual)
+ (memq class gnus-visual))
+ t))))
+
(defcustom gnus-mouse-face
(condition-case ()
(if (gnus-visual-p 'mouse-face 'highlight)
,(nnheader-concat gnus-cache-directory "active"))))
"List of predefined (convenience) servers.")
-(defvar gnus-topic-indentation "");; Obsolete variable.
+(defvar gnus-topic-indentation "") ;; Obsolete variable.
(defconst gnus-article-mark-lists
'((marked . tick) (replied . reply)
(bookmarks . bookmark) (dormant . dormant)
(scored . score) (saved . save)
(cached . cache) (downloadable . download)
- (unsendable . unsend) (forwarded . forward)))
+ (unsendable . unsend) (forwarded . forward)
+ (recent . recent) (seen . seen)))
+
+(defconst gnus-article-special-mark-lists
+ '((seen range)
+ (killed range)
+ (bookmark tuple)
+ (score tuple)))
+
+;; Propagate flags to server, with the following exceptions:
+;; `seen' is private to each gnus installation
+;; `cache' is a internal gnus flag for each gnus installation
+;; `download' is a agent flag private to each gnus installation
+;; `unsend' are for nndraft groups only
+;; `score' is not a proper mark
+(defconst gnus-article-unpropagated-mark-lists
+ '(seen cache download unsend score)
+ "Marks that shouldn't be propagated to backends.
+Typical marks are those that make no sense in a standalone backend,
+such as a mark that says whether an article is stored in the cache
+(which doesn't make sense in a standalone backend).")
(defvar gnus-headers-retrieved-by nil)
(defvar gnus-article-reply nil)
("gnus-msg" (gnus-summary-send-map keymap)
gnus-article-mail gnus-copy-article-buffer gnus-extended-version)
("gnus-msg" :interactive t
- gnus-group-post-news gnus-group-mail gnus-summary-post-news
+ gnus-group-post-news gnus-group-mail gnus-group-news
+ gnus-summary-post-news gnus-summary-news-other-window
gnus-summary-followup gnus-summary-followup-with-original
gnus-summary-cancel-article gnus-summary-supersede-article
gnus-post-news gnus-summary-reply gnus-summary-reply-with-original
gnus-summary-wide-reply-with-original
gnus-summary-post-forward gnus-summary-wide-reply-with-original
gnus-summary-post-forward)
- ("gnus-picon" :interactive t gnus-article-display-picons
- gnus-group-display-picons gnus-picons-article-display-x-face
- gnus-picons-display-x-face)
- ("gnus-picon" gnus-picons-buffer-name)
+ ("gnus-picon" :interactive t gnus-treat-from-picon)
("gnus-gl" bbb-login bbb-logout bbb-grouplens-group-p
gnus-grouplens-mode)
("smiley" :interactive t gnus-smiley-display)
gnus-unplugged gnus-agentize gnus-agent-batch)
("gnus-vm" :interactive t gnus-summary-save-in-vm
gnus-summary-save-article-vm)
- ("gnus-draft" :interactive t gnus-draft-mode gnus-group-send-drafts)
+ ("gnus-draft" :interactive t gnus-draft-mode gnus-group-send-queue)
("gnus-mlspl" gnus-group-split gnus-group-split-fancy)
("gnus-mlspl" :interactive t gnus-group-split-setup
gnus-group-split-update))))
;;; gnus-sum.el thingies
-(defcustom gnus-summary-line-format "%U%R%z%I%(%[%4L: %-20,20n%]%) %s\n"
+(defcustom gnus-summary-line-format "%U%R%z%I%(%[%4L: %-23,23n%]%) %s\n"
"*The format specification of the lines in the summary buffer.
It works along the same lines as a normal formatting string,
%x Contents of the Xref: header (string)
%D Date of the article (string)
%d Date of the article (string) in DD-MMM format
+%o Date of the article (string) in YYYYMMDD`T'HHMMSS format
%M Message-id of the article (string)
%r References of the article (string)
%c Number of characters in the article (integer)
%L Number of lines in the article (integer)
%I Indentation based on thread level (a string of spaces)
+%B A complex trn-style thread tree (string)
+ The variables `gnus-sum-thread-*' can be used for customization.
%T A string with two possible values: 80 spaces if the article
is on thread level two or larger and 0 spaces on level one
%R \"A\" if this article has been replied to, \" \" otherwise (character)
(defmacro gnus-get-info (group)
`(nth 2 (gnus-gethash ,group gnus-newsrc-hashtb)))
-;; Byte-compiler warning.
-(defvar gnus-visual)
-;; Find out whether the gnus-visual TYPE is wanted.
-(defun gnus-visual-p (&optional type class)
- (and gnus-visual ; Has to be non-nil, at least.
- (if (not type) ; We don't care about type.
- gnus-visual
- (if (listp gnus-visual) ; It's a list, so we check it.
- (or (memq type gnus-visual)
- (memq class gnus-visual))
- t))))
-
;;; Load the compatability functions.
(require 'gnus-ems)
;;; Gnus Utility Functions
;;;
+(defun gnus-find-subscribed-addresses ()
+ "Return a regexp matching the addresses of all subscribed mail groups.
+It consists of the `to-address' or `to-list' parameter of all groups
+with a `subscribed' parameter."
+ (let (group address addresses)
+ (dolist (entry (cdr gnus-newsrc-alist))
+ (setq group (car entry))
+ (when (gnus-group-find-parameter group 'subscribed)
+ (setq address (or (gnus-group-fast-parameter group 'to-address)
+ (gnus-group-fast-parameter group 'to-list)))
+ (when address
+ (push address addresses))))
+ (list (mapconcat 'regexp-quote addresses "\\|"))))
(defmacro gnus-string-or (&rest strings)
"Return the first element of STRINGS that is a non-blank string.
(insert (message gnus-version))
(message gnus-version)))
-(defun gnus-continuum-version (version)
+(defun gnus-continuum-version (&optional version)
"Return VERSION as a floating point number."
+ (interactive)
+ (unless version
+ (setq version gnus-version))
(when (or (string-match "^\\([^ ]+\\)? ?Gnus v?\\([0-9.]+\\)$" version)
(string-match "^\\(.?\\)gnus-\\([0-9.]+\\)$" version))
(let ((alpha (and (match-beginning 1) (match-string 1 version)))
0))
(string-to-number
(if (zerop major)
- (format "%s00%02d%02d"
- (if (member alpha '("(ding)" "d"))
- "4.99"
- (+ 5 (* 0.02
- (abs
- (- (mm-char-int (aref (downcase alpha) 0))
- (mm-char-int ?t))))
- -0.01))
- minor least)
+ (format "%s00%02d%02d"
+ (if (member alpha '("(ding)" "d"))
+ "4.99"
+ (+ 5 (* 0.02
+ (abs
+ (- (mm-char-int (aref (downcase alpha) 0))
+ (mm-char-int ?t))))
+ -0.01))
+ minor least)
(format "%d.%02d%02d" major minor least))))))
-(defun gnus-info-find-node ()
+(defun gnus-info-find-node (&optional nodename)
"Find Info documentation of Gnus."
(interactive)
;; Enlarge info window if needed.
(let (gnus-info-buffer)
- (Info-goto-node (cadr (assq major-mode gnus-info-nodes)))
+ (Info-goto-node (or nodename (cadr (assq major-mode gnus-info-nodes))))
(setq gnus-info-buffer (current-buffer))
(gnus-configure-windows 'info)))
(defun gnus-news-group-p (group &optional article)
"Return non-nil if GROUP (and ARTICLE) come from a news server."
- (or (gnus-member-of-valid 'post group) ; Ordinary news group.
- (and (gnus-member-of-valid 'post-mail group) ; Combined group.
- (if (or (null article)
- (not (< article 0)))
- (eq (gnus-request-type group article) 'news)
- (if (not (vectorp article))
- nil
- ;; It's a real article.
- (eq (gnus-request-type group (mail-header-id article))
- 'news))))))
+ (cond ((gnus-member-of-valid 'post group) ;Ordinary news group
+ t) ;is news of course.
+ ((not (gnus-member-of-valid 'post-mail group)) ;Non-combined.
+ nil) ;must be mail then.
+ ((vectorp article) ;Has header info.
+ (eq (gnus-request-type group (mail-header-id article)) 'news))
+ ((null article) ;Hasn't header info
+ (eq (gnus-request-type group) 'news)) ;(unknown ==> mail)
+ ((< article 0) ;Virtual message
+ nil) ;we don't know, guess mail.
+ (t ;Has positive number
+ (eq (gnus-request-type group article) 'news)))) ;use it.
;; Returns a list of writable groups.
(defun gnus-writable-groups ()
(not (string= (nth 1 method) "")))
(concat "+" (nth 1 method)))))
+(defsubst gnus-method-to-full-server-name (method)
+ (format "%s+%s" (car method) (nth 1 method)))
+
(defun gnus-group-prefixed-name (group method)
"Return the whole name from GROUP and METHOD."
(and (stringp method) (setq method (gnus-server-to-method method)))
(if (or (not method)
- (gnus-server-equal method "native"))
+ (gnus-server-equal method "native")
+ (string-match ":" group))
group
(concat (gnus-method-to-server-name method) ":" group)))
(defun gnus-parameters-get-parameter (group)
"Return the group parameters for GROUP from `gnus-parameters'."
- (let ((alist gnus-parameters)
- params-list)
- (while alist
- (when (string-match (caar alist) group)
- (setq params-list
- (nconc (copy-sequence (cdar alist))
- params-list)))
- (pop alist))
+ (let (params-list)
+ (dolist (elem gnus-parameters)
+ (when (string-match (car elem) group)
+ (setq params-list
+ (nconc (gnus-expand-group-parameters
+ (car elem) (cdr elem) group)
+ params-list))))
params-list))
+(defun gnus-expand-group-parameter (match value group)
+ "Use MATCH to expand VALUE in GROUP."
+ (with-temp-buffer
+ (insert group)
+ (goto-char (point-min))
+ (while (re-search-forward match nil t)
+ (replace-match value))
+ (buffer-string)))
+
+(defun gnus-expand-group-parameters (match parameters group)
+ "Go through PARAMETERS and expand them according to the match data."
+ (let (new)
+ (dolist (elem parameters)
+ (if (and (stringp (cdr elem))
+ (string-match "\\\\" (cdr elem)))
+ (push (cons (car elem)
+ (gnus-expand-group-parameter match (cdr elem) group))
+ new)
+ (push elem new)))
+ new))
+
+(defun gnus-group-fast-parameter (group symbol &optional allow-list)
+ "For GROUP, return the value of SYMBOL.
+
+You should call this in the `gnus-group-buffer' buffer.
+The function `gnus-group-find-parameter' will do that for you."
+ ;; The speed trick: No cons'ing and quit early.
+ (or (let ((params (funcall gnus-group-get-parameter-function group)))
+ ;; Start easy, check the "real" group parameters.
+ (gnus-group-parameter-value params symbol allow-list))
+ ;; We didn't found it there, try `gnus-parameters'.
+ (let ((result nil)
+ (head nil)
+ (tail gnus-parameters))
+ ;; A good old-fashioned non-cl loop.
+ (while tail
+ (setq head (car tail)
+ tail (cdr tail))
+ ;; The car is regexp matching for matching the group name.
+ (when (string-match (car head) group)
+ ;; The cdr is the parameters.
+ (setq result (gnus-group-parameter-value (cdr head)
+ symbol allow-list))
+ (when result
+ ;; Expand if necessary.
+ (if (and (stringp result) (string-match "\\\\" result))
+ (setq result (gnus-expand-group-parameter (car head)
+ result group)))
+ ;; Exit the loop early.
+ (setq tail nil))))
+ ;; Done.
+ result)))
+
(defun gnus-group-find-parameter (group &optional symbol allow-list)
"Return the group parameters for GROUP.
-If SYMBOL, return the value of that symbol in the group parameters."
+If SYMBOL, return the value of that symbol in the group parameters.
+
+If you call this function inside a loop, consider using the faster
+`gnus-group-fast-parameter' instead."
(save-excursion
(set-buffer gnus-group-buffer)
- (let ((parameters
- (nconc
- (copy-sequence
- (funcall gnus-group-get-parameter-function group))
- (gnus-parameters-get-parameter group))))
- (if symbol
- (gnus-group-parameter-value parameters symbol allow-list)
+ (if symbol
+ (gnus-group-fast-parameter group symbol allow-list)
+ (let ((parameters
+ (nconc
+ (copy-sequence
+ (funcall gnus-group-get-parameter-function group))
+ (gnus-parameters-get-parameter group))))
parameters))))
(defun gnus-group-get-parameter (group &optional symbol allow-list)
depth (+ depth 1)))
depth))))
;; Separate foreign select method from group name and collapse.
- ;; If method contains a server, collapse to non-domain server name,
+ ;; If method contains a server, collapse to non-domain server name,
;; otherwise collapse to select method.
(let* ((colon (string-match ":" group))
(server (and colon (substring group 0 colon)))
(or gnus-override-method
(and (not group)
gnus-select-method)
- (and (not (gnus-group-entry group));; a new group
+ (and (not (gnus-group-entry group)) ;; a new group
(gnus-group-name-to-method group))
(let ((info (or info (gnus-get-info group)))
method)
(defun gnus-read-method (prompt)
"Prompt the user for a method.
Allow completion over sensible values."
- (let* ((open-servers
+ (let* ((open-servers
(mapcar (lambda (i) (cons (format "%s:%s" (caar i) (cadar i)) i))
gnus-opened-servers))
(valid-methods
(let ((window (get-buffer-window gnus-group-buffer)))
(cond (window
(select-frame (window-frame window)))
- (t
- (select-frame (make-frame)))))
+ (t
+ (select-frame (make-frame)))))
(gnus arg))
;;(setq thing ? ; this is a comment
startup level. If ARG is non-nil and not a positive number, Gnus will
prompt the user for the name of an NNTP server to use."
(interactive "P")
+ (unless (byte-code-function-p (symbol-function 'gnus))
+ (message "You should byte-compile Gnus")
+ (sit-for 2))
(gnus-1 arg dont-connect slave))
;; Allow redefinition of Gnus functions.
--- /dev/null
+;;; hex-util.el --- Functions to encode/decode hexadecimal string.
+
+;; Copyright (C) 1999, 2001 Free Software Foundation, Inc.
+
+;; Author: Shuhei KOBAYASHI <shuhei@aqua.ocn.ne.jp>
+;; Keywords: data
+
+;; This file is part of FLIM (Faithful Library about Internet Message).
+
+;; 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 2, 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; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile
+ (defmacro hex-char-to-num (chr)
+ (` (let ((chr (, chr)))
+ (cond
+ ((and (<= ?a chr)(<= chr ?f)) (+ (- chr ?a) 10))
+ ((and (<= ?A chr)(<= chr ?F)) (+ (- chr ?A) 10))
+ ((and (<= ?0 chr)(<= chr ?9)) (- chr ?0))
+ (t (error "Invalid hexadecimal digit `%c'" chr))))))
+ (defmacro num-to-hex-char (num)
+ (` (aref "0123456789abcdef" (, num)))))
+
+(defun decode-hex-string (string)
+ "Decode hexadecimal STRING to octet string."
+ (let* ((len (length string))
+ (dst (make-string (/ len 2) 0))
+ (idx 0)(pos 0))
+ (while (< pos len)
+;;; logior and lsh are not byte-coded.
+;;; (aset dst idx (logior (lsh (hex-char-to-num (aref string pos)) 4)
+;;; (hex-char-to-num (aref string (1+ pos)))))
+ (aset dst idx (+ (* (hex-char-to-num (aref string pos)) 16)
+ (hex-char-to-num (aref string (1+ pos)))))
+ (setq idx (1+ idx)
+ pos (+ 2 pos)))
+ dst))
+
+(defun encode-hex-string (string)
+ "Encode octet STRING to hexadecimal string."
+ (let* ((len (length string))
+ (dst (make-string (* len 2) 0))
+ (idx 0)(pos 0))
+ (while (< pos len)
+;;; logand and lsh are not byte-coded.
+;;; (aset dst idx (num-to-hex-char (logand (lsh (aref string pos) -4) 15)))
+ (aset dst idx (num-to-hex-char (/ (aref string pos) 16)))
+ (setq idx (1+ idx))
+;;; (aset dst idx (num-to-hex-char (logand (aref string pos) 15)))
+ (aset dst idx (num-to-hex-char (% (aref string pos) 16)))
+ (setq idx (1+ idx)
+ pos (1+ pos)))
+ dst))
+
+(provide 'hex-util)
+
+;;; hex-util.el ends here
;;; ietf-drums.el --- Functions for parsing RFC822bis headers
-;; Copyright (C) 1998, 1999, 2000
+;; Copyright (C) 1998, 1999, 2000, 2001, 2002
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
(defun ietf-drums-parse-addresses (string)
"Parse STRING and return a list of MAILBOX / DISPLAY-NAME pairs."
- (with-temp-buffer
- (ietf-drums-init string)
- (let ((beg (point))
- pairs c)
- (while (not (eobp))
- (setq c (char-after))
- (cond
- ((memq c '(?\" ?< ?\())
- (forward-sexp 1))
- ((eq c ?,)
- (push (ietf-drums-parse-address (buffer-substring beg (point)))
- pairs)
- (forward-char 1)
- (setq beg (point)))
- (t
- (forward-char 1))))
- (push (ietf-drums-parse-address (buffer-substring beg (point)))
- pairs)
- (nreverse pairs))))
+ (if (null string)
+ nil
+ (with-temp-buffer
+ (ietf-drums-init string)
+ (let ((beg (point))
+ pairs c address)
+ (while (not (eobp))
+ (setq c (char-after))
+ (cond
+ ((memq c '(?\" ?< ?\())
+ (condition-case nil
+ (forward-sexp 1)
+ (error
+ (skip-chars-forward "^,"))))
+ ((eq c ?,)
+ (setq address
+ (condition-case nil
+ (ietf-drums-parse-address
+ (buffer-substring beg (point)))
+ (error nil)))
+ (if address (push address pairs))
+ (forward-char 1)
+ (setq beg (point)))
+ (t
+ (forward-char 1))))
+ (setq address
+ (condition-case nil
+ (ietf-drums-parse-address
+ (buffer-substring beg (point)))
+ (error nil)))
+ (if address (push address pairs))
+ (nreverse pairs)))))
(defun ietf-drums-unfold-fws ()
"Unfold folding white space in the current buffer."
;;; imap.el --- imap library
-;; Copyright (C) 1998, 1999, 2000
+;; Copyright (C) 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
;; Author: Simon Josefsson <jas@pdc.kth.se>
;;
;; Mailbox commands:
;;
-;; imap-mailbox-get, imap-mailbox-map, imap-current-mailbox,
+;; imap-mailbox-get, imap-mailbox-map, imap-current-mailbox,
;; imap-current-mailbox-p, imap-search, imap-mailbox-select,
;; imap-mailbox-examine, imap-mailbox-unselect, imap-mailbox-expunge
;; imap-mailbox-close, imap-mailbox-create, imap-mailbox-delete
;; imap-fetch-asynch, imap-fetch,
;; imap-current-message, imap-list-to-message-set,
;; imap-message-get, imap-message-map
-;; imap-message-envelope-date, imap-message-envelope-subject,
+;; imap-message-envelope-date, imap-message-envelope-subject,
;; imap-message-envelope-from, imap-message-envelope-sender,
;; imap-message-envelope-reply-to, imap-message-envelope-to,
;; imap-message-envelope-cc, imap-message-envelope-bcc
;; => "X-Sieve: cmu-sieve 1.3^M\nX-Username: <jas@pdc.kth.se>^M\r...."
;;
;; Todo:
-;;
+;;
;; o Parse UIDs as strings? We need to overcome the 28 bit limit somehow.
;; o Don't use `read' at all (important places already fixed)
;; o Accept list of articles instead of message set string in most
:group 'imap
:type '(repeat string))
-(defcustom imap-ssl-program '("openssl s_client -ssl3 -connect %s:%p"
- "openssl s_client -ssl2 -connect %s:%p"
- "s_client -ssl3 -connect %s:%p"
- "s_client -ssl2 -connect %s:%p")
+(defcustom imap-ssl-program '("openssl s_client -quiet -ssl3 -connect %s:%p"
+ "openssl s_client -quiet -ssl2 -connect %s:%p"
+ "s_client -quiet -ssl3 -connect %s:%p"
+ "s_client -quiet -ssl2 -connect %s:%p")
"A string, or list of strings, containing commands for SSL connections.
Within a string, %s is replaced with the server address and %p with
port number on server. The program should accept IMAP commands on
:group 'imap
:type '(repeat string))
-(defvar imap-shell-host "gateway"
- "Hostname of rlogin proxy.")
+(defcustom imap-process-connection-type nil
+ "*Value for `process-connection-type' to use for Kerberos4 and GSSAPI."
+ :group 'imap
+ :type 'boolean)
+
+(defcustom imap-use-utf7 t
+ "If non-nil, do utf7 encoding/decoding of mailbox names.
+Since the UTF7 decoding currently only decodes into ISO-8859-1
+characters, you may disable this decoding if you need to access UTF7
+encoded mailboxes which doesn't translate into ISO-8859-1."
+ :group 'imap
+ :type 'boolean)
-(defvar imap-default-user (user-login-name)
- "Default username to use.")
+(defcustom imap-log nil
+ "If non-nil, a imap session trace is placed in *imap-log* buffer."
+ :group 'imap
+ :type 'boolean)
-(defvar imap-error nil
- "Error codes from the last command.")
+(defcustom imap-debug nil
+ "If non-nil, random debug spews are placed in *imap-debug* buffer."
+ :group 'imap
+ :type 'boolean)
+
+(defcustom imap-shell-host "gateway"
+ "Hostname of rlogin proxy."
+ :group 'imap
+ :type 'string)
+
+(defcustom imap-default-user (user-login-name)
+ "Default username to use."
+ :group 'imap
+ :type 'string)
;; Various variables.
(starttls imap-starttls-p imap-starttls-open))
"Definition of network streams.
-(NAME CHECK OPEN)
+\(NAME CHECK OPEN)
NAME names the stream, CHECK is a function returning non-nil if the
server support the stream and OPEN is a function for opening the
stream.")
-(defvar imap-authenticators '(gssapi
+(defvar imap-authenticators '(gssapi
kerberos4
digest-md5
cram-md5
anonymous)
"Priority of authenticators to consider when authenticating to server.")
-(defvar imap-authenticator-alist
+(defvar imap-authenticator-alist
'((gssapi imap-gssapi-auth-p imap-gssapi-auth)
(kerberos4 imap-kerberos4-auth-p imap-kerberos4-auth)
(cram-md5 imap-cram-md5-p imap-cram-md5-auth)
(digest-md5 imap-digest-md5-p imap-digest-md5-auth))
"Definition of authenticators.
-(NAME CHECK AUTHENTICATE)
+\(NAME CHECK AUTHENTICATE)
NAME names the authenticator. CHECK is a function returning non-nil if
the server support the authenticator and AUTHENTICATE is a function
-for doing the actuall authentification.")
+for doing the actual authentication.")
-(defvar imap-use-utf7 t
- "If non-nil, do utf7 encoding/decoding of mailbox names.
-Since the UTF7 decoding currently only decodes into ISO-8859-1
-characters, you may disable this decoding if you need to access UTF7
-encoded mailboxes which doesn't translate into ISO-8859-1.")
+(defvar imap-error nil
+ "Error codes from the last command.")
;; Internal constants. Change theese and die.
imap-process
imap-calculate-literal-size-first
imap-mailbox-data))
+(defconst imap-log-buffer "*imap-log*")
+(defconst imap-debug-buffer "*imap-debug*")
;; Internal variables.
(defvar imap-username nil)
(defvar imap-password nil)
(defvar imap-calculate-literal-size-first nil)
-(defvar imap-state 'closed
+(defvar imap-state 'closed
"IMAP state.
Valid states are `closed', `initial', `nonauth', `auth', `selected'
and `examine'.")
(defvar imap-reached-tag 0
"Lower limit on command tags that have been parsed.")
-(defvar imap-failed-tags nil
+(defvar imap-failed-tags nil
"Alist of tags that failed.
Each element is a list with four elements; tag (a integer), response
state (a symbol, `OK', `NO' or `BAD'), response code (a string), and
"Non-nil indicates that the server emitted a continuation request.
The actually value is really the text on the continuation line.")
-(defvar imap-log nil
- "Name of buffer for imap session trace.
-For example: (setq imap-log \"*imap-log*\")")
-
-(defvar imap-debug nil ;"*imap-debug*"
- "Name of buffer for random debug spew.
-For example: (setq imap-debug \"*imap-debug*\")")
+(defvar imap-callbacks nil
+ "List of response tags and callbacks, on the form `(number . function)'.
+The function should take two arguments, the first the IMAP tag and the
+second the status (OK, NO, BAD etc) of the command.")
\f
;; Utility functions:
+(defun imap-remassoc (key alist)
+ "Delete by side effect any elements of LIST whose car is `equal' to KEY.
+The modified LIST is returned. If the first member
+of LIST has a car that is `equal' to KEY, there is no way to remove it
+by side effect; therefore, write `(setq foo (remassoc key foo))' to be
+sure of changing the value of `foo'."
+ (when alist
+ (if (equal key (caar alist))
+ (cdr alist)
+ (setcdr alist (imap-remassoc key (cdr alist)))
+ alist)))
+
(defsubst imap-disable-multibyte ()
"Enable multibyte in the current buffer."
(when (fboundp 'set-buffer-multibyte)
(and string
(condition-case ()
(utf7-encode string t)
- (error (message
+ (error (message
"imap: Could not UTF7 encode `%s', using it unencoded..."
string)
string)))
(let* ((port (or port imap-default-port))
(coding-system-for-read imap-coding-system-for-read)
(coding-system-for-write imap-coding-system-for-write)
- (process (start-process
+ (process-connection-type imap-process-connection-type)
+ (process (start-process
name buffer shell-file-name shell-command-switch
(format-spec
cmd
(setq imap-client-eol "\n"
imap-calculate-literal-size-first t)
(while (and (memq (process-status process) '(open run))
+ (set-buffer buffer) ;; XXX "blue moon" nntp.el bug
(goto-char (point-min))
- ;; cyrus 1.6.x (13? < x <= 22) queries capabilities
+ ;; cyrus 1.6.x (13? < x <= 22) queries capabilities
(or (while (looking-at "^C:")
(forward-line))
t)
(accept-process-output process 1)
(sit-for 1))
(and imap-log
- (with-current-buffer (get-buffer-create imap-log)
+ (with-current-buffer (get-buffer-create imap-log-buffer)
(imap-disable-multibyte)
(buffer-disable-undo)
(goto-char (point-max))
(delete-process process)
nil)))))
done))
-
+
(defun imap-gssapi-stream-p (buffer)
(imap-capability 'AUTH=GSSAPI buffer))
(let* ((port (or port imap-default-port))
(coding-system-for-read imap-coding-system-for-read)
(coding-system-for-write imap-coding-system-for-write)
- (process (start-process
+ (process-connection-type imap-process-connection-type)
+ (process (start-process
name buffer shell-file-name shell-command-switch
(format-spec
cmd
(setq imap-client-eol "\n"
imap-calculate-literal-size-first t)
(while (and (memq (process-status process) '(open run))
+ (set-buffer buffer) ;; XXX "blue moon" nntp.el bug
(goto-char (point-min))
- ;; cyrus 1.6.x (13? < x <= 22) queries capabilities
+ ;; cyrus 1.6.x (13? < x <= 22) queries capabilities
(or (while (looking-at "^C:")
(forward-line))
t)
(accept-process-output process 1)
(sit-for 1))
(and imap-log
- (with-current-buffer (get-buffer-create imap-log)
+ (with-current-buffer (get-buffer-create imap-log-buffer)
(imap-disable-multibyte)
(buffer-disable-undo)
(goto-char (point-max))
(let ((cmds (if (listp imap-ssl-program) imap-ssl-program
(list imap-ssl-program)))
cmd done)
+ (ignore-errors (require 'ssl))
(while (and (not done) (setq cmd (pop cmds)))
(message "imap: Opening SSL connection with `%s'..." cmd)
(let* ((port (or port imap-default-ssl-port))
(with-current-buffer buffer
(goto-char (point-min))
(while (and (memq (process-status process) '(open run))
+ (set-buffer buffer) ;; XXX "blue moon" nntp.el bug
(goto-char (point-max))
(forward-line -1)
(not (imap-parse-greeting)))
(accept-process-output process 1)
(sit-for 1))
(and imap-log
- (with-current-buffer (get-buffer-create imap-log)
+ (with-current-buffer (get-buffer-create imap-log-buffer)
(imap-disable-multibyte)
(buffer-disable-undo)
(goto-char (point-max))
(progn
(message "imap: Opening SSL connection with `%s'...done" cmd)
done)
- (message "imap: Opening SSL connection with `%s'...failed" cmd)
+ (message "imap: Opening SSL connection with `%s'...failed" cmd)
nil)))
(defun imap-network-p (buffer)
(process (open-network-stream name buffer server port)))
(when process
(while (and (memq (process-status process) '(open run))
+ (set-buffer buffer) ;; XXX "blue moon" nntp.el bug
(goto-char (point-min))
(not (imap-parse-greeting)))
(accept-process-output process 1)
(sit-for 1))
(and imap-log
- (with-current-buffer (get-buffer-create imap-log)
+ (with-current-buffer (get-buffer-create imap-log-buffer)
(imap-disable-multibyte)
(buffer-disable-undo)
(goto-char (point-max))
(let* ((port (or port imap-default-port))
(coding-system-for-read imap-coding-system-for-read)
(coding-system-for-write imap-coding-system-for-write)
- (process (start-process
+ (process (start-process
name buffer shell-file-name shell-command-switch
(format-spec
cmd
?l imap-default-user)))))
(when process
(while (and (memq (process-status process) '(open run))
+ (set-buffer buffer) ;; XXX "blue moon" nntp.el bug
(goto-char (point-min))
(not (imap-parse-greeting)))
(accept-process-output process 1)
(sit-for 1))
(and imap-log
- (with-current-buffer (get-buffer-create imap-log)
+ (with-current-buffer (get-buffer-create imap-log-buffer)
(imap-disable-multibyte)
(buffer-disable-undo)
(goto-char (point-max))
(progn
(message "imap: Opening IMAP connection with `%s'...done" cmd)
done)
- (message "imap: Opening IMAP connection with `%s'...failed" cmd)
+ (message "imap: Opening IMAP connection with `%s'...failed" cmd)
nil)))
(defun imap-starttls-p (buffer)
(message "imap: Connecting with STARTTLS...")
(when process
(while (and (memq (process-status process) '(open run))
+ (set-buffer buffer) ;; XXX "blue moon" nntp.el bug
(goto-char (point-min))
(not (imap-parse-greeting)))
(accept-process-output process 1)
(sit-for 1))
(and imap-log
- (with-current-buffer (get-buffer-create imap-log)
+ (with-current-buffer (get-buffer-create imap-log-buffer)
(buffer-disable-undo)
(goto-char (point-max))
(insert-buffer-substring buffer)))
done)
(message "imap: Connecting with STARTTLS...failed")
nil)))
-
+
;; Server functions; authenticator stuff:
(defun imap-interactive-login (buffer loginfunc)
it where sucessful authenticating itself to the server, nil otherwise.
Returns t if login was successful, nil otherwise."
(with-current-buffer buffer
- (make-variable-buffer-local 'imap-username)
- (make-variable-buffer-local 'imap-password)
+ (make-local-variable 'imap-username)
+ (make-local-variable 'imap-password)
(let (user passwd ret)
;; (condition-case ()
(while (or (not user) (not passwd))
(setq user (or imap-username
- (read-from-minibuffer
+ (read-from-minibuffer
(concat "IMAP username for " imap-server ": ")
(or user imap-default-user))))
(setq passwd (or imap-password
(imap-read-passwd
- (concat "IMAP password for " user "@"
+ (concat "IMAP password for " user "@"
imap-server ": "))))
(when (and user passwd)
(if (funcall loginfunc user passwd)
ret)))
(defun imap-gssapi-auth-p (buffer)
- (imap-capability 'AUTH=GSSAPI buffer))
+ (and (imap-capability 'AUTH=GSSAPI buffer)
+ (catch 'imtest-found
+ (let (prg (prgs imap-gssapi-program))
+ (while (setq prg (pop prgs))
+ (condition-case ()
+ (and (call-process (substring prg 0 (string-match " " prg)))
+ (throw 'imtest-found t))
+ (error nil)))))))
(defun imap-gssapi-auth (buffer)
(message "imap: Authenticating using GSSAPI...%s"
(eq imap-stream 'gssapi))
(defun imap-kerberos4-auth-p (buffer)
- (imap-capability 'AUTH=KERBEROS_V4 buffer))
+ (and (imap-capability 'AUTH=KERBEROS_V4 buffer)
+ (catch 'imtest-found
+ (let (prg (prgs imap-kerberos4-program))
+ (while (setq prg (pop prgs))
+ (condition-case ()
+ (and (call-process (substring prg 0 (string-match " " prg)))
+ (throw 'imtest-found t))
+ (error nil)))))))
(defun imap-kerberos4-auth (buffer)
(message "imap: Authenticating using Kerberos 4...%s"
(if done
(message "imap: Authenticating using CRAM-MD5...done")
(message "imap: Authenticating using CRAM-MD5...failed"))))
-
-
(defun imap-login-p (buffer)
(and (not (imap-capability 'LOGINDISABLED buffer))
(defun imap-login-auth (buffer)
"Login to server using the LOGIN command."
(message "imap: Plaintext authentication...")
- (imap-interactive-login buffer
+ (imap-interactive-login buffer
(lambda (user passwd)
- (imap-ok-p (imap-send-command-wait
- (concat "LOGIN \"" user "\" \""
+ (imap-ok-p (imap-send-command-wait
+ (concat "LOGIN \"" user "\" \""
passwd "\""))))))
(defun imap-anonymous-p (buffer)
(message "imap: Loging in anonymously...")
(with-current-buffer buffer
(imap-ok-p (imap-send-command-wait
- (concat "LOGIN anonymous \"" (concat (user-login-name) "@"
+ (concat "LOGIN anonymous \"" (concat (user-login-name) "@"
(system-name)) "\"")))))
(defun imap-digest-md5-p (buffer)
(imap-interactive-login
buffer
(lambda (user passwd)
- (let ((tag
+ (let ((tag
(imap-send-command
(list
"AUTHENTICATE DIGEST-MD5"
(digest-md5-parse-digest-challenge
(base64-decode-string challenge))
(let* ((digest-uri
- (digest-md5-digest-uri
+ (digest-md5-digest-uri
"imap" (digest-md5-challenge 'realm)))
(response
- (digest-md5-digest-response
+ (digest-md5-digest-response
user passwd digest-uri)))
(base64-encode-string response 'no-line-break))))
)))
imap-current-message nil
imap-state 'initial
imap-process (condition-case ()
- (funcall (nth 2 (assq imap-stream
+ (funcall (nth 2 (assq imap-stream
imap-stream-alist))
"imap" buffer imap-server imap-port)
((error quit) nil)))
(with-current-buffer (get-buffer-create buffer)
(if (imap-opened buffer)
(imap-close buffer))
- (mapcar 'make-variable-buffer-local imap-local-variables)
+ (mapcar 'make-local-variable imap-local-variables)
(imap-disable-multibyte)
(buffer-disable-undo)
(setq imap-server (or server imap-server))
(let ((streams imap-streams))
(while (setq stream (pop streams))
(if (funcall (nth 1 (assq stream imap-stream-alist)) buffer)
- (setq stream-changed (not (eq (or imap-stream
+ (setq stream-changed (not (eq (or imap-stream
imap-default-stream)
stream))
imap-stream stream
(if (imap-open-1 buffer)
(message "imap: Reconnecting with stream `%s'...done"
imap-stream)
- (message "imap: Reconnecting with stream `%s'...failed"
+ (message "imap: Reconnecting with stream `%s'...failed"
imap-stream))
(setq imap-capability nil))
(if (imap-opened buffer)
(when (and (null imap-auth) (not (eq imap-state 'auth)))
(let ((auths imap-authenticators))
(while (setq auth (pop auths))
- (if (funcall (nth 1 (assq auth imap-authenticator-alist))
+ (if (funcall (nth 1 (assq auth imap-authenticator-alist))
buffer)
(setq imap-auth auth
auths nil)))
(or (eq imap-state 'auth)
(eq imap-state 'select)
(eq imap-state 'examine))
- (make-variable-buffer-local 'imap-username)
- (make-variable-buffer-local 'imap-password)
+ (make-local-variable 'imap-username)
+ (make-local-variable 'imap-password)
(if user (setq imap-username user))
(if passwd (setq imap-password passwd))
(if (funcall (nth 2 (assq imap-auth imap-authenticator-alist)) buffer)
"Close connection to server in BUFFER.
If BUFFER is nil, the current buffer is used."
(with-current-buffer (or buffer (current-buffer))
- (and (imap-opened)
- (not (imap-ok-p (imap-send-command-wait "LOGOUT")))
- (message "Server %s didn't let me log out" imap-server))
+ (when (imap-opened)
+ (imap-send-command-wait "LOGOUT"))
(when (and imap-process
(memq (process-status imap-process) '(open run)))
(delete-process imap-process))
(defun imap-mailbox-map-1 (func &optional mailbox-decoder buffer)
(with-current-buffer (or buffer (current-buffer))
(let (result)
- (mapatoms
+ (mapatoms
(lambda (s)
(push (funcall func (if mailbox-decoder
(funcall mailbox-decoder (symbol-name s))
imap-current-mailbox
(setq imap-current-mailbox mailbox)
(if (imap-ok-p (imap-send-command-wait
- (concat (if examine "EXAMINE" "SELECT") " \""
+ (concat (if examine "EXAMINE" "SELECT") " \""
mailbox "\"")))
(progn
(setq imap-message-data (make-vector imap-message-prime 0)
;; Failed SELECT/EXAMINE unselects current mailbox
(setq imap-current-mailbox nil))))
-(defun imap-mailbox-select (mailbox &optional examine buffer)
+(defun imap-mailbox-select (mailbox &optional examine buffer)
(with-current-buffer (or buffer (current-buffer))
- (imap-utf7-decode
+ (imap-utf7-decode
(imap-mailbox-select-1 (imap-utf7-encode mailbox) examine))))
(defun imap-mailbox-examine-1 (mailbox &optional buffer)
(with-current-buffer (or buffer (current-buffer))
- (imap-mailbox-select-1 mailbox 'exmine)))
+ (imap-mailbox-select-1 mailbox 'examine)))
(defun imap-mailbox-examine (mailbox &optional buffer)
"Examine MAILBOX on server in BUFFER."
- (imap-mailbox-select mailbox 'exmine buffer))
+ (imap-mailbox-select mailbox 'examine buffer))
(defun imap-mailbox-unselect (&optional buffer)
"Close current folder in BUFFER, without expunging articles."
(when (or (eq imap-state 'auth)
(and (imap-capability 'UNSELECT)
(imap-ok-p (imap-send-command-wait "UNSELECT")))
- (and (imap-ok-p
+ (and (imap-ok-p
(imap-send-command-wait (concat "EXAMINE \""
imap-current-mailbox
"\"")))
imap-state 'auth)
t)))
-(defun imap-mailbox-expunge (&optional buffer)
+(defun imap-mailbox-expunge (&optional asynch buffer)
"Expunge articles in current folder in BUFFER.
+If ASYNCH, do not wait for succesful completion of the command.
If BUFFER is nil the current buffer is assumed."
(with-current-buffer (or buffer (current-buffer))
(when (and imap-current-mailbox (not (eq imap-state 'examine)))
- (imap-ok-p (imap-send-command-wait "EXPUNGE")))))
+ (if asynch
+ (imap-send-command "EXPUNGE")
+ (imap-ok-p (imap-send-command-wait "EXPUNGE"))))))
-(defun imap-mailbox-close (&optional buffer)
+(defun imap-mailbox-close (&optional asynch buffer)
"Expunge articles and close current folder in BUFFER.
+If ASYNCH, do not wait for succesful completion of the command.
If BUFFER is nil the current buffer is assumed."
(with-current-buffer (or buffer (current-buffer))
- (when (and imap-current-mailbox
- (imap-ok-p (imap-send-command-wait "CLOSE")))
- (setq imap-current-mailbox nil
- imap-message-data nil
- imap-state 'auth)
+ (when imap-current-mailbox
+ (if asynch
+ (imap-add-callback (imap-send-command "CLOSE")
+ `(lambda (tag status)
+ (message "IMAP mailbox `%s' closed... %s"
+ imap-current-mailbox status)
+ (when (eq ,imap-current-mailbox
+ imap-current-mailbox)
+ ;; Don't wipe out data if another mailbox
+ ;; was selected...
+ (setq imap-current-mailbox nil
+ imap-message-data nil
+ imap-state 'auth))))
+ (when (imap-ok-p (imap-send-command-wait "CLOSE"))
+ (setq imap-current-mailbox nil
+ imap-message-data nil
+ imap-state 'auth)))
t)))
(defun imap-mailbox-create-1 (mailbox)
(imap-send-command-wait (list "RENAME \"" oldname "\" "
"\"" newname "\""))))))
-(defun imap-mailbox-lsub (&optional root reference add-delimiter buffer)
+(defun imap-mailbox-lsub (&optional root reference add-delimiter buffer)
"Return a list of subscribed mailboxes on server in BUFFER.
If ROOT is non-nil, only list matching mailboxes. If ADD-DELIMITER is
non-nil, a hierarchy delimiter is added to root. REFERENCE is a
(imap-mailbox-map-1 (lambda (mailbox)
(imap-mailbox-put 'lsub nil mailbox)))
(when (imap-ok-p
- (imap-send-command-wait
+ (imap-send-command-wait
(concat "LSUB \"" reference "\" \"" (imap-utf7-encode root)
(and add-delimiter (imap-mailbox-get-1 'delimiter root))
"%\"")))
(imap-mailbox-map-1 (lambda (mailbox)
(imap-mailbox-put 'list nil mailbox)))
(when (imap-ok-p
- (imap-send-command-wait
+ (imap-send-command-wait
(concat "LIST \"" reference "\" \"" (imap-utf7-encode root)
(and add-delimiter (imap-mailbox-get-1 'delimiter root))
"%\"")))
"Send the SUBSCRIBE command on the mailbox to server in BUFFER.
Returns non-nil if successful."
(with-current-buffer (or buffer (current-buffer))
- (imap-ok-p (imap-send-command-wait (concat "SUBSCRIBE \""
+ (imap-ok-p (imap-send-command-wait (concat "SUBSCRIBE \""
(imap-utf7-encode mailbox)
"\"")))))
"Send the SUBSCRIBE command on the mailbox to server in BUFFER.
Returns non-nil if successful."
(with-current-buffer (or buffer (current-buffer))
- (imap-ok-p (imap-send-command-wait (concat "UNSUBSCRIBE "
+ (imap-ok-p (imap-send-command-wait (concat "UNSUBSCRIBE "
(imap-utf7-encode mailbox)
"\"")))))
or 'unseen. If ITEMS is a list of symbols, a list of values is
returned, if ITEMS is a symbol only it's value is returned."
(with-current-buffer (or buffer (current-buffer))
- (when (imap-ok-p
+ (when (imap-ok-p
(imap-send-command-wait (list "STATUS \""
(imap-utf7-encode mailbox)
"\" "
(format "%s"
(if (listp items)
- items
+ items
(list items))))))
(if (listp items)
(mapcar (lambda (item)
(mapconcat
(lambda (item)
(if (consp item)
- (format "%d:%d"
- (car item) (cdr item))
+ (format "%d:%d"
+ (car item) (cdr item))
(format "%d" item)))
(if (and (listp range) (not (listp (cdr range))))
(list range) ;; make (1 . 2) into ((1 . 2))
UIDS can be a string, number or a list of numbers. If RECEIVE
is non-nil return theese properties."
(with-current-buffer (or buffer (current-buffer))
- (when (imap-ok-p (imap-send-command-wait
+ (when (imap-ok-p (imap-send-command-wait
(format "%sFETCH %s %s" (if nouidfetch "" "UID ")
(if (listp uids)
(imap-list-to-message-set uids)
(imap-message-get uid receive)))
uids)
(imap-message-get uids receive))))))
-
+
(defun imap-message-put (uid propname value &optional buffer)
(with-current-buffer (or buffer (current-buffer))
(if imap-message-data
(imap-mailbox-put 'search 'dummy)
(when (imap-ok-p (imap-send-command-wait (concat "UID SEARCH " predicate)))
(if (eq (imap-mailbox-get-1 'search imap-current-mailbox) 'dummy)
- (error "Missing SEARCH response to a SEARCH command")
+ (progn
+ (message "Missing SEARCH response to a SEARCH command (server not RFC compliant)...")
+ nil)
(imap-mailbox-get-1 'search imap-current-mailbox)))))
(defun imap-message-flag-permanent-p (flag &optional mailbox buffer)
(imap-ok-p (imap-send-command-wait cmd)))))
(or no-copyuid
(imap-message-copyuid-1 mailbox)))))))
-
+
(defun imap-message-appenduid-1 (mailbox)
(if (imap-capability 'UIDPLUS)
(imap-mailbox-get-1 'appenduid mailbox)
(let ((mailbox (imap-utf7-encode mailbox)))
(with-current-buffer (or buffer (current-buffer))
(and (let ((imap-current-target-mailbox mailbox))
- (imap-ok-p
- (imap-send-command-wait
+ (imap-ok-p
+ (imap-send-command-wait
(list "APPEND \"" mailbox "\" " article))))
(imap-message-appenduid-1 mailbox)))))
-
+
(defun imap-body-lines (body)
"Return number of lines in article by looking at the mime bodystructure BODY."
(if (listp body)
(and from
(concat (aref from 0)
(if (aref from 0) " <")
- (aref from 2)
- "@"
+ (aref from 2)
+ "@"
(aref from 3)
(if (aref from 0) ">"))))
\f
;; Internal functions.
+(defun imap-add-callback (tag func)
+ (setq imap-callbacks (append (list (cons tag func)) imap-callbacks)))
+
(defun imap-send-command-1 (cmdstr)
(setq cmdstr (concat cmdstr imap-client-eol))
(and imap-log
- (with-current-buffer (get-buffer-create imap-log)
+ (with-current-buffer (get-buffer-create imap-log-buffer)
(imap-disable-multibyte)
(buffer-disable-undo)
(goto-char (point-max))
(replace-match eol)))
(if (not calcfirst)
(setq size (buffer-size))))
- (setq cmdstr
+ (setq cmdstr
(concat cmdstr (format "{%d}" size))))
(unwind-protect
(progn
(imap-send-command-1 cmdstr)
(setq cmdstr nil)
(if (not (eq (imap-wait-for-tag tag) 'INCOMPLETE))
- (setq command nil);; abort command if no cont-req
+ (setq command nil) ;; abort command if no cont-req
(let ((process imap-process)
(stream imap-stream)
(eol imap-client-eol))
(with-current-buffer cmd
(and imap-log
(with-current-buffer (get-buffer-create
- imap-log)
+ imap-log-buffer)
(imap-disable-multibyte)
(buffer-disable-undo)
(goto-char (point-max))
(setq cmdstr nil)
(unwind-protect
(if (not (eq (imap-wait-for-tag tag) 'INCOMPLETE))
- (setq command nil);; abort command if no cont-req
+ (setq command nil) ;; abort command if no cont-req
(setq command (cons (funcall cmd imap-continuation)
command)))
(setq imap-continuation nil)))
(defun imap-wait-for-tag (tag &optional buffer)
(with-current-buffer (or buffer (current-buffer))
- (while (and (null imap-continuation)
- (< imap-reached-tag tag))
- (or (and (not (memq (process-status imap-process) '(open run)))
- (sit-for 1))
- (let ((len (/ (point-max) 1024))
- message-log-max)
- (unless (< len 10)
- (message "imap read: %dk" len))
- (accept-process-output imap-process 1))))
- (message "")
- (or (assq tag imap-failed-tags)
- (if imap-continuation
- 'INCOMPLETE
- 'OK))))
+ (let (imap-have-messaged)
+ (while (and (null imap-continuation)
+ (memq (process-status imap-process) '(open run))
+ (< imap-reached-tag tag))
+ (let ((len (/ (point-max) 1024))
+ message-log-max)
+ (unless (< len 10)
+ (setq imap-have-messaged t)
+ (message "imap read: %dk" len))
+ (accept-process-output imap-process 1)))
+ (when imap-have-messaged
+ (message ""))
+ (and (memq (process-status imap-process) '(open run))
+ (or (assq tag imap-failed-tags)
+ (if imap-continuation
+ 'INCOMPLETE
+ 'OK))))))
(defun imap-sentinel (process string)
(delete-process process))
(goto-char (point-max))
(insert string)
(and imap-log
- (with-current-buffer (get-buffer-create imap-log)
+ (with-current-buffer (get-buffer-create imap-log-buffer)
(imap-disable-multibyte)
(buffer-disable-undo)
(goto-char (point-max))
(eq imap-state 'examine))
(imap-parse-response))
(t
- (message "Unknown state %s in arrival filter"
+ (message "Unknown state %s in arrival filter"
imap-state)))
(delete-region (point-min) (point-max))))))))
(defsubst imap-parse-astring ()
(or (imap-parse-string)
- (buffer-substring (point)
+ (buffer-substring (point)
(if (re-search-forward "[(){ \r\n%*\"\\]" nil t)
(goto-char (1- (match-end 0)))
(end-of-line)
;;
;; addr-adl = nstring
;; ; Holds route from [RFC-822] route-addr if
-;; ; non-NIL
+;; ; non-nil
;;
;; addr-host = nstring
-;; ; NIL indicates [RFC-822] group syntax.
+;; ; nil indicates [RFC-822] group syntax.
;; ; Otherwise, holds [RFC-822] domain name
;;
;; addr-mailbox = nstring
-;; ; NIL indicates end of [RFC-822] group; if
-;; ; non-NIL and addr-host is NIL, holds
+;; ; nil indicates end of [RFC-822] group; if
+;; ; non-nil and addr-host is nil, holds
;; ; [RFC-822] group name.
;; ; Otherwise, holds [RFC-822] local-part
;; ; after removing [RFC-822] quoting
;;
;; addr-name = nstring
-;; ; If non-NIL, holds phrase from [RFC-822]
+;; ; If non-nil, holds phrase from [RFC-822]
;; ; mailbox after removing [RFC-822] quoting
;;
(when (eq (char-after) ?\))
(imap-forward)
(nreverse addresses)))
- (assert (imap-parse-nil))))
+ (assert (imap-parse-nil) t "In imap-parse-address-list")))
;; mailbox = "INBOX" / astring
;; ; INBOX is case-insensitive. All case variants of
(FLAGS (imap-mailbox-put 'flags (imap-parse-flag-list)))
(LIST (imap-parse-data-list 'list))
(LSUB (imap-parse-data-list 'lsub))
- (SEARCH (imap-mailbox-put
- 'search
+ (SEARCH (imap-mailbox-put
+ 'search
(read (concat "(" (buffer-substring (point) (point-max)) ")"))))
(STATUS (imap-parse-status))
- (CAPABILITY (setq imap-capability
- (read (concat "(" (upcase (buffer-substring
- (point) (point-max)))
- ")"))))
+ (CAPABILITY (setq imap-capability
+ (read (concat "(" (upcase (buffer-substring
+ (point) (point-max)))
+ ")"))))
(ACL (imap-parse-acl))
(t (case (prog1 (read (current-buffer))
(imap-forward))
(search-forward "]")))
(imap-forward))
(setq text (buffer-substring (point) (point-max)))
- (push (list token status code text)
+ (push (list token status code text)
imap-failed-tags))))
(BAD (progn
(setq imap-reached-tag (max imap-reached-tag token))
(push (list token status code text) imap-failed-tags)
(error "Internal error, tag %s status %s code %s text %s"
token status code text))))
- (t (message "Garbage: %s" (buffer-string))))))))))
+ (t (message "Garbage: %s" (buffer-string))))
+ (when (assq token imap-callbacks)
+ (funcall (cdr (assq token imap-callbacks)) token status)
+ (setq imap-callbacks
+ (imap-remassoc token imap-callbacks)))))))))
;; resp-text = ["[" resp-text-code "]" SP] text
;;
;; resp-text-code = "ALERT" /
;; "BADCHARSET [SP "(" astring *(SP astring) ")" ] /
-;; "NEWNAME" SP string SP string /
+;; "NEWNAME" SP string SP string /
;; "PARSE" /
-;; "PERMANENTFLAGS" SP "("
+;; "PERMANENTFLAGS" SP "("
;; [flag-perm *(SP flag-perm)] ")" /
-;; "READ-ONLY" /
-;; "READ-WRITE" /
+;; "READ-ONLY" /
+;; "READ-WRITE" /
;; "TRYCREATE" /
-;; "UIDNEXT" SP nz-number /
+;; "UIDNEXT" SP nz-number /
;; "UIDVALIDITY" SP nz-number /
;; "UNSEEN" SP nz-number /
;; resp-text-atom [SP 1*<any TEXT-CHAR except "]">]
;; ; delimits between two numbers inclusive.
;; ; Example: 2,4:7,9,12:* is 2,4,5,6,7,9,12,13,
;; ; 14,15 for a mailbox with 15 messages.
-;;
+;;
;; sequence-num = nz-number / "*"
;; ; * is the largest number in use. For message
;; ; sequence numbers, it is the number of messages
;; "BODY" ["STRUCTURE"] SPACE body /
;; "BODY" section ["<" number ">"] SPACE nstring /
;; "UID" SPACE uniqueid) ")"
-;;
+;;
;; date_time ::= <"> date_day_fixed "-" date_month "-" date_year
;; SPACE time SPACE zone <">
-;;
+;;
;; section ::= "[" [section_text / (nz_number *["." nz_number]
;; ["." (section_text / "MIME")])] "]"
-;;
+;;
;; section_text ::= "HEADER" / "HEADER.FIELDS" [".NOT"]
;; SPACE header_list / "TEXT"
-;;
+;;
;; header_fld_name ::= astring
-;;
+;;
;; header_list ::= "(" 1#header_fld_name ")"
(defsubst imap-parse-header-list ()
(nreverse strlist))))
(defsubst imap-parse-fetch-body-section ()
- (let ((section
+ (let ((section
(buffer-substring (point) (1- (re-search-forward "[] ]" nil t)))))
(if (eq (char-before) ? )
(prog1
(defun imap-parse-fetch (response)
(when (eq (char-after) ?\()
- (let (uid flags envelope internaldate rfc822 rfc822header rfc822text
- rfc822size body bodydetail bodystructure)
+ (let (uid flags envelope internaldate rfc822 rfc822header rfc822text
+ rfc822size body bodydetail bodystructure flags-empty)
(while (not (eq (char-after) ?\)))
(imap-forward)
(let ((token (read (current-buffer))))
(cond ((eq token 'UID)
(setq uid (ignore-errors (read (current-buffer)))))
((eq token 'FLAGS)
- (setq flags (imap-parse-flag-list)))
+ (setq flags (imap-parse-flag-list))
+ (if (not flags)
+ (setq flags-empty 't)))
((eq token 'ENVELOPE)
(setq envelope (imap-parse-envelope)))
((eq token 'INTERNALDATE)
(when uid
(setq imap-current-message uid)
(imap-message-put uid 'UID uid)
- (and flags (imap-message-put uid 'FLAGS flags))
+ (and (or flags flags-empty) (imap-message-put uid 'FLAGS flags))
(and envelope (imap-message-put uid 'ENVELOPE envelope))
(and internaldate (imap-message-put uid 'INTERNALDATE internaldate))
(and rfc822 (imap-message-put uid 'RFC822 rfc822))
;; mailbox-data = ...
;; "STATUS" SP mailbox SP "("
-;; [status-att SP number
+;; [status-att SP number
;; *(SP status-att SP number)] ")"
;; ...
;;
((eq token 'UNSEEN)
(imap-mailbox-put 'unseen (read (current-buffer)) mailbox))
(t
- (message "Unknown status data %s in mailbox %s ignored"
+ (message "Unknown status data %s in mailbox %s ignored"
token mailbox))))))))
;; acl_data ::= "ACL" SPACE mailbox *(SPACE identifier SPACE
(defun imap-parse-flag-list ()
(let (flag-list start)
- (assert (eq (char-after) ?\())
+ (assert (eq (char-after) ?\() t "In imap-parse-flag-list")
(while (and (not (eq (char-after) ?\)))
- (setq start (progn (imap-forward) (point)))
+ (setq start (progn
+ (imap-forward)
+ ;; next line for Courier IMAP bug.
+ (skip-chars-forward " ")
+ (point)))
(> (skip-chars-forward "^ )" (imap-point-at-eol)) 0))
(push (buffer-substring start (point)) flag-list))
- (assert (eq (char-after) ?\)))
+ (assert (eq (char-after) ?\)) t "In imap-parse-flag-list")
(imap-forward)
(nreverse flag-list)))
(defun imap-parse-envelope ()
(when (eq (char-after) ?\()
(imap-forward)
- (vector (prog1 (imap-parse-nstring);; date
+ (vector (prog1 (imap-parse-nstring) ;; date
(imap-forward))
- (prog1 (imap-parse-nstring);; subject
+ (prog1 (imap-parse-nstring) ;; subject
(imap-forward))
- (prog1 (imap-parse-address-list);; from
+ (prog1 (imap-parse-address-list) ;; from
(imap-forward))
- (prog1 (imap-parse-address-list);; sender
+ (prog1 (imap-parse-address-list) ;; sender
(imap-forward))
- (prog1 (imap-parse-address-list);; reply-to
+ (prog1 (imap-parse-address-list) ;; reply-to
(imap-forward))
- (prog1 (imap-parse-address-list);; to
+ (prog1 (imap-parse-address-list) ;; to
(imap-forward))
- (prog1 (imap-parse-address-list);; cc
+ (prog1 (imap-parse-address-list) ;; cc
(imap-forward))
- (prog1 (imap-parse-address-list);; bcc
+ (prog1 (imap-parse-address-list) ;; bcc
(imap-forward))
- (prog1 (imap-parse-nstring);; in-reply-to
+ (prog1 (imap-parse-nstring) ;; in-reply-to
(imap-forward))
- (prog1 (imap-parse-nstring);; message-id
+ (prog1 (imap-parse-nstring) ;; message-id
(imap-forward)))))
;; body-fld-param = "(" string SP string *(SP string SP string) ")" / nil
(defsubst imap-parse-string-list ()
- (cond ((eq (char-after) ?\();; body-fld-param
+ (cond ((eq (char-after) ?\() ;; body-fld-param
(let (strlist str)
(imap-forward)
(while (setq str (imap-parse-string))
(while (eq (char-after) ?\ )
(imap-forward)
(push (imap-parse-body-extension) b-e))
- (assert (eq (char-after) ?\)))
+ (assert (eq (char-after) ?\)) t "In imap-parse-body-extension")
(imap-forward)
(nreverse b-e))
(or (imap-parse-number)
(defsubst imap-parse-body-ext ()
(let (ext)
- (when (eq (char-after) ?\ );; body-fld-dsp
+ (when (eq (char-after) ?\ ) ;; body-fld-dsp
(imap-forward)
(let (dsp)
(if (eq (char-after) ?\()
(imap-forward)
(push (imap-parse-string-list) dsp)
(imap-forward))
- (assert (imap-parse-nil)))
+ (assert (imap-parse-nil) t "In imap-parse-body-ext"))
(push (nreverse dsp) ext))
- (when (eq (char-after) ?\ );; body-fld-lang
+ (when (eq (char-after) ?\ ) ;; body-fld-lang
(imap-forward)
(if (eq (char-after) ?\()
(push (imap-parse-string-list) ext)
(push (imap-parse-nstring) ext))
- (while (eq (char-after) ?\ );; body-extension
+ (while (eq (char-after) ?\ ) ;; body-extension
(imap-forward)
(setq ext (append (imap-parse-body-extension) ext)))))
ext))
(let (subbody)
(while (and (eq (char-after) ?\()
(setq subbody (imap-parse-body)))
- ;; buggy stalker communigate pro 3.0 insert a SPC between
+ ;; buggy stalker communigate pro 3.0 insert a SPC between
;; parts in multiparts
(when (and (eq (char-after) ?\ )
(eq (char-after (1+ (point))) ?\())
(imap-forward))
(push subbody body))
(imap-forward)
- (push (imap-parse-string) body);; media-subtype
- (when (eq (char-after) ?\ );; body-ext-mpart:
+ (push (imap-parse-string) body) ;; media-subtype
+ (when (eq (char-after) ?\ ) ;; body-ext-mpart:
(imap-forward)
- (if (eq (char-after) ?\();; body-fld-param
+ (if (eq (char-after) ?\() ;; body-fld-param
(push (imap-parse-string-list) body)
(push (and (imap-parse-nil) nil) body))
(setq body
- (append (imap-parse-body-ext) body)));; body-ext-...
- (assert (eq (char-after) ?\)))
+ (append (imap-parse-body-ext) body))) ;; body-ext-...
+ (assert (eq (char-after) ?\)) t "In imap-parse-body")
(imap-forward)
(nreverse body))
- (push (imap-parse-string) body);; media-type
+ (push (imap-parse-string) body) ;; media-type
(imap-forward)
- (push (imap-parse-string) body);; media-subtype
+ (push (imap-parse-string) body) ;; media-subtype
(imap-forward)
;; next line for Sun SIMS bug
(and (eq (char-after) ? ) (imap-forward))
- (if (eq (char-after) ?\();; body-fld-param
+ (if (eq (char-after) ?\() ;; body-fld-param
(push (imap-parse-string-list) body)
(push (and (imap-parse-nil) nil) body))
(imap-forward)
- (push (imap-parse-nstring) body);; body-fld-id
+ (push (imap-parse-nstring) body) ;; body-fld-id
(imap-forward)
- (push (imap-parse-nstring) body);; body-fld-desc
+ (push (imap-parse-nstring) body) ;; body-fld-desc
(imap-forward)
;; next `or' for Sun SIMS bug, it regard body-fld-enc as a
- ;; nstring and return NIL instead of defaulting back to 7BIT
+ ;; nstring and return nil instead of defaulting back to 7BIT
;; as the standard says.
- (push (or (imap-parse-nstring) "7BIT") body);; body-fld-enc
+ (push (or (imap-parse-nstring) "7BIT") body) ;; body-fld-enc
(imap-forward)
- (push (imap-parse-number) body);; body-fld-octets
+ (push (imap-parse-number) body) ;; body-fld-octets
- ;; ok, we're done parsing the required parts, what comes now is one
+ ;; ok, we're done parsing the required parts, what comes now is one
;; of three things:
;;
;; envelope (then we're parsing body-type-msg)
;; body-fld-lines (then we're parsing body-type-text)
;; body-ext-1part (then we're parsing body-type-basic)
;;
- ;; the problem is that the two first are in turn optionally followed
- ;; by the third. So we parse the first two here (if there are any)...
+ ;; the problem is that the two first are in turn optionally followed
+;; by the third. So we parse the first two here (if there are any)...
(when (eq (char-after) ?\ )
(imap-forward)
(let (lines)
- (cond ((eq (char-after) ?\();; body-type-msg:
- (push (imap-parse-envelope) body);; envelope
+ (cond ((eq (char-after) ?\() ;; body-type-msg:
+ (push (imap-parse-envelope) body) ;; envelope
(imap-forward)
- (push (imap-parse-body) body);; body
+ (push (imap-parse-body) body) ;; body
;; buggy stalker communigate pro 3.0 doesn't print
;; number of lines in message/rfc822 attachment
(if (eq (char-after) ?\))
(push 0 body)
(imap-forward)
(push (imap-parse-number) body))) ;; body-fld-lines
- ((setq lines (imap-parse-number)) ;; body-type-text:
- (push lines body)) ;; body-fld-lines
+ ((setq lines (imap-parse-number)) ;; body-type-text:
+ (push lines body)) ;; body-fld-lines
(t
- (backward-char))))) ;; no match...
+ (backward-char))))) ;; no match...
;; ...and then parse the third one here...
- (when (eq (char-after) ?\ );; body-ext-1part:
+ (when (eq (char-after) ?\ ) ;; body-ext-1part:
(imap-forward)
- (push (imap-parse-nstring) body);; body-fld-md5
- (setq body (append (imap-parse-body-ext) body)));; body-ext-1part..
-
- (assert (eq (char-after) ?\)))
+ (push (imap-parse-nstring) body) ;; body-fld-md5
+ (setq body (append (imap-parse-body-ext) body))) ;; body-ext-1part..
+
+ (assert (eq (char-after) ?\)) t "In imap-parse-body 2")
(imap-forward)
(nreverse body)))))
(when imap-debug ; (untrace-all)
(require 'trace)
- (buffer-disable-undo (get-buffer-create imap-debug))
- (mapcar (lambda (f) (trace-function-background f imap-debug))
+ (buffer-disable-undo (get-buffer-create imap-debug-buffer))
+ (mapcar (lambda (f) (trace-function-background f imap-debug-buffer))
'(
imap-read-passwd
imap-utf7-encode
imap-parse-body-extension
imap-parse-body
)))
-
+
(provide 'imap)
;;; imap.el ends here
(maybe-fbind '(babel-fetch
babel-wash create-image decode-coding-string display-graphic-p
+ replace-regexp-in-string
+ bbdb-complete-name
display-time-event-handler
find-image font-create-object gnus-mule-get-coding-system
font-lock-set-defaults
+ find-coding-systems-string
image-size image-type-available-p insert-image
+ image-type-from-file-header
make-temp-file message-xmas-redefine
mail-aliases-setup mm-copy-tree
mule-write-region-no-coding-system put-image
ring-elements
+ charsetp sort-coding-systems
+ coding-system-p coding-system-list
+ propertize make-mode-line-mouse2-map
+ frames-on-display-list
+ make-mode-line-mouse-map
rmail-select-summary rmail-summary-exists rmail-update-summary
+ rmail-toggle-header
sc-cite-regexp set-font-family set-font-size temp-directory
string-as-multibyte
tool-bar-add-item tool-bar-add-item-from-menu
(maybe-bind '(adaptive-fill-first-line-regexp
adaptive-fill-regexp babel-history babel-translations
default-enable-multibyte-characters
+ enable-multibyte-characters
display-time-mail-function imap-password mail-mode-hook
+ filladapt-mode
mc-pgp-always-sign
+ gpg-unabbrev-trust-alist
nnoo-definition-alist
+ current-language-environment
+ language-info-alist
url-current-callback-func url-be-asynchronous
url-current-callback-data url-working-buffer
url-current-mime-headers w3-meta-charset-content-type-regexp
+ rmail-enable-mime-composing
+ rmail-insert-mime-forwarded-message-function
w3-meta-content-type-charset-regexp))
(if (featurep 'xemacs)
make-overlay mouse-minibuffer-check mouse-movement-p
mouse-scroll-subr overlay-buffer overlay-end
overlay-get overlay-lists overlay-put
+ overlays-in
overlay-start posn-point posn-window
read-event read-event run-with-idle-timer
set-buffer-multibyte set-char-table-range
set-face-stipple set-frame-face-alist track-mouse
url-retrieve w3-form-encode-xwfu window-at
window-edges x-color-values x-popup-menu browse-url
- frame-char-height frame-char-width))
+ frame-char-height frame-char-width
+ url-generic-parse-url xml-parse-region))
(maybe-bind '(buffer-display-table
buffer-file-coding-system font-lock-defaults
global-face-data gnus-article-x-face-too-ugly
enable-multibyte-characters help-echo-owns-message))
(maybe-fbind '(Info-goto-node
add-submenu annotation-glyph annotationp babel-as-string
- button-press-event-p char-int characterp color-instance-name
+ button-press-event-p characterp color-instance-name
color-instance-rgb-components color-name delete-annotation
device-class device-on-window-system-p device-type
display-error event-glyph event-object event-point
set-face-doc-string set-glyph-image set-glyph-property
specifier-instance url-generic-parse-url
valid-image-instantiator-format-p w3-do-setup
- window-pixel-height window-pixel-width)))
+ window-pixel-height window-pixel-width
+ xml-parse-region)))
(require 'custom)
(defalias 'mail-narrow-to-head 'ietf-drums-narrow-to-header)
(defalias 'mail-quote-string 'ietf-drums-quote-string)
+(defalias 'mail-header-fold-field 'rfc2047-fold-field)
+(defalias 'mail-header-unfold-field 'rfc2047-unfold-field)
(defalias 'mail-header-narrow-to-field 'rfc2047-narrow-to-field)
+(defalias 'mail-header-field-value 'rfc2047-field-value)
+
(defalias 'mail-encode-encoded-word-region 'rfc2047-encode-region)
(defalias 'mail-encode-encoded-word-buffer 'rfc2047-encode-message-header)
(defalias 'mail-encode-encoded-word-string 'rfc2047-encode-string)
(autoload 'nnheader-run-at-time "nnheader"))
(require 'format-spec)
(require 'mm-util)
+(require 'message) ;; for `message-directory'
(defgroup mail-source nil
"The mail-fetching library."
:group 'mail-source
:type 'sexp)
+(defcustom mail-source-flash t
+ "*If non-nil, flash periodically when mail is available."
+ :group 'mail-source
+ :type 'boolean)
+
(defcustom mail-source-crash-box "~/.emacs-mail-crash-box"
"File where mail will be stored while processing it."
:group 'mail-source
:type 'file)
-(defcustom mail-source-directory "~/Mail/"
+(defcustom mail-source-directory message-directory
"Directory where files (if any) will be stored."
:group 'mail-source
:type 'directory)
:group 'mail-source
:type 'number)
+(defcustom mail-source-movemail-program nil
+ "If non-nil, name of program for fetching new mail."
+ :group 'mail-source
+ :type '(choice (const nil) string))
+
;;; Internal variables.
(defvar mail-source-string ""
(setq found (mail-source-callback
callback mail-source-crash-box)))
(+ found
- (condition-case err
+ (if (or debug-on-quit debug-on-error)
(funcall function source callback)
- (error
- (unless (yes-or-no-p
- (format "Mail source error (%s). Continue? " err))
- (error "Cannot get new mail."))
- 0))))))))
+ (condition-case err
+ (funcall function source callback)
+ (error
+ (unless (yes-or-no-p
+ (format "Mail source error (%s). Continue? " err))
+ (error "Cannot get new mail"))
+ 0)))))))))
(defun mail-source-make-complex-temp-name (prefix)
(let ((newname (make-temp-name prefix))
'call-process
(append
(list
- (expand-file-name "movemail" exec-directory)
+ (or mail-source-movemail-program
+ (expand-file-name "movemail" exec-directory))
nil errors nil from to)))))
(when (file-exists-p to)
(set-file-modes to mail-source-default-file-modes))
- (if (and (not (buffer-modified-p errors))
+ (if (and (or (not (buffer-modified-p errors))
+ (zerop (buffer-size errors)))
(zerop result))
;; No output => movemail won.
t
(pop3-port port)
(pop3-authentication-scheme
(if (eq authentication 'apop) 'apop 'pass)))
- (condition-case err
+ (if (or debug-on-quit debug-on-error)
(save-excursion (pop3-movemail mail-source-crash-box))
- (error
- ;; We nix out the password in case the error
- ;; was because of a wrong password being given.
- (setq mail-source-password-cache
- (delq (assoc from mail-source-password-cache)
- mail-source-password-cache))
- (signal (car err) (cdr err))))))))
+ (condition-case err
+ (save-excursion (pop3-movemail mail-source-crash-box))
+ (error
+ ;; We nix out the password in case the error
+ ;; was because of a wrong password being given.
+ (setq mail-source-password-cache
+ (delq (assoc from mail-source-password-cache)
+ mail-source-password-cache))
+ (signal (car err) (cdr err)))))))))
(if result
(progn
(when (eq authentication 'password)
(pop3-port port)
(pop3-authentication-scheme
(if (eq authentication 'apop) 'apop 'pass)))
- (condition-case err
+ (if (or debug-on-quit debug-on-error)
(save-excursion (pop3-get-message-count))
- (error
- ;; We nix out the password in case the error
- ;; was because of a wrong password being given.
- (setq mail-source-password-cache
- (delq (assoc from mail-source-password-cache)
- mail-source-password-cache))
- (signal (car err) (cdr err))))))))
+ (condition-case err
+ (save-excursion (pop3-get-message-count))
+ (error
+ ;; We nix out the password in case the error
+ ;; was because of a wrong password being given.
+ (setq mail-source-password-cache
+ (delq (assoc from mail-source-password-cache)
+ mail-source-password-cache))
+ (signal (car err) (cdr err)))))))))
(if result
;; Inform display-time that we have new mail.
(setq mail-source-new-mail-available (> result 0))
(defun mail-source-new-mail-p ()
"Handler for `display-time' to indicate when new mail is available."
+ ;; Flash (ie. ring the visible bell) if mail is available.
+ (if (and mail-source-flash mail-source-new-mail-available)
+ (let ((visible-bell t))
+ (ding)))
;; Only report flag setting; flag is updated on a different schedule.
mail-source-new-mail-available)
mail-source-idle-time-delay
nil
(lambda ()
- (mail-source-check-pop mail-source-primary-source)
- (setq mail-source-report-new-mail-idle-timer nil))))
+ (unwind-protect
+ (mail-source-check-pop mail-source-primary-source)
+ (setq mail-source-report-new-mail-idle-timer nil)))))
;; Since idle timers created when Emacs is already in the idle
;; state don't get activated until Emacs _next_ becomes idle, we
;; need to force our timer to be considered active now. We do
This only works when `display-time' is enabled."
(interactive "P")
(if (not mail-source-primary-source)
- (error "Need to set `mail-source-primary-source' to check for new mail."))
+ (error "Need to set `mail-source-primary-source' to check for new mail"))
(let ((on (if (null arg)
(not mail-source-report-new-mail)
(> (prefix-numeric-value arg) 0))))
(push (cons from imap-password) mail-source-password-cache)))
;; if predicate is nil, use all uids
(dolist (uid (imap-search (or predicate "1:*") buf))
- (when (setq str (imap-fetch uid "RFC822.PEEK" 'RFC822 nil buf))
+ (when (setq str
+ (if (imap-capability 'IMAP4rev1 buf)
+ (caddar (imap-fetch uid "BODY.PEEK[]"
+ 'BODYDETAIL nil buf))
+ (imap-fetch uid "RFC822.PEEK" 'RFC822 nil buf)))
(push uid remove)
(insert "From imap " (current-time-string) "\n")
(save-excursion
fetchflag nil buf))
(if dontexpunge
(imap-mailbox-unselect buf)
- (imap-mailbox-close buf))
+ (imap-mailbox-close nil buf))
(imap-close buf))
(imap-close buf)
;; We nix out the password in case the error
(defcustom mailcap-download-directory nil
"*Directory to which `mailcap-save-binary-file' downloads files by default.
-Nil means your home directory."
+nil means your home directory."
:type '(choice (const :tag "Home directory" nil)
directory)
:group 'mailcap)
+(defvar mailcap-poor-system-types
+ '(ms-dos ms-windows windows-nt win32 w32 mswindows)
+ "Systems that don't have a Unix-like directory hierarchy.")
+
;;;
;;; Utility functions
;;;
"Text of warning message displayed by `mailcap-maybe-eval'.
Make sure that this text consists only of few text lines. Otherwise,
Gnus might fail to display all of it.")
-
+
(defun mailcap-maybe-eval ()
"Maybe evaluate a buffer of Emacs Lisp code."
(let ((lisp-buffer (current-buffer)))
(cond
(path nil)
((getenv "MAILCAPS") (setq path (getenv "MAILCAPS")))
- ((memq system-type '(ms-dos ms-windows windows-nt))
+ ((memq system-type mailcap-poor-system-types)
(setq path '("~/.mailcap" "~/mail.cap" "~/etc/mail.cap")))
(t (setq path
;; This is per RFC 1524, specifically
((or (null request) (equal request ""))
(mailcap-unescape-mime-test (cdr (assq 'viewer viewer)) info))
((stringp request)
- (if (or (eq request 'test) (eq request 'viewer))
- (mailcap-unescape-mime-test
- (cdr-safe (assoc request viewer)) info)))
+ (mailcap-unescape-mime-test
+ (cdr-safe (assoc request viewer)) info))
((eq request 'all)
passed)
(t
(cond
(path nil)
((getenv "MIMETYPES") (setq path (getenv "MIMETYPES")))
- ((memq system-type '(ms-dos ms-windows windows-nt))
+ ((memq system-type mailcap-poor-system-types)
(setq path '("~/mime.typ" "~/etc/mime.typ")))
(t (setq path
;; mime.types seems to be the normal name, definitely so
-;;; message.el --- composing mail and news messages -*- coding: iso-latin-1 -*-
+;;; message.el --- composing mail and news messages
;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
(eval-when-compile
(require 'cl)
- (defvar gnus-list-identifiers)) ; gnus-sum is required where necessary
+ (defvar gnus-list-identifiers)) ; gnus-sum is required where necessary
+(require 'canlock)
(require 'mailheader)
(require 'nnheader)
;; This is apparently necessary even though things are autoloaded:
(require 'mail-abbrevs))
(require 'mail-parse)
(require 'mml)
+(require 'rfc822)
+(eval-and-compile
+ (autoload 'sha1 "sha1-el"))
(defgroup message '((user-mail-address custom-variable)
(user-full-name custom-variable))
`new-text', `quoting-style', `redirected-followup', `signature',
`approved', `sender', `empty', `empty-headers', `message-id', `from',
`subject', `shorten-followup-to', `existing-newsgroups',
-`buffer-file-name', `unchanged', `newsgroups'."
+`buffer-file-name', `unchanged', `newsgroups', `reply-to'."
:group 'message-news
:type '(repeat sexp)) ; Fixme: improve this
'(From Subject Date (optional . In-Reply-To) Message-ID Lines
(optional . User-Agent))
"*Headers to be generated or prompted for when mailing a message.
-RFC822 required that From, Date, To, Subject and Message-ID be
+It is recommended that From, Date, To, Subject and Message-ID be
included. Organization, Lines and User-Agent are optional."
:group 'message-mail
:group 'message-headers
:group 'message-headers
:type 'regexp)
-(defcustom message-ignored-supersedes-headers "^Path:\\|^Date\\|^NNTP-Posting-Host:\\|^Xref:\\|^Lines:\\|^Received:\\|^X-From-Line:\\|^X-Trace:\\|^X-Complaints-To:\\|Return-Path:\\|^Supersedes:\\|^NNTP-Posting-Date:\\|^X-Trace:\\|^X-Complaints-To:"
+(defcustom message-ignored-supersedes-headers "^Path:\\|^Date\\|^NNTP-Posting-Host:\\|^Xref:\\|^Lines:\\|^Received:\\|^X-From-Line:\\|^X-Trace:\\|^X-Complaints-To:\\|Return-Path:\\|^Supersedes:\\|^NNTP-Posting-Date:\\|^X-Trace:\\|^X-Complaints-To:\\|^Cancel-Lock:\\|^Cancel-Key:"
"*Header lines matching this regexp will be deleted before posting.
It's best to delete old Path and Date headers before posting to avoid
any confusion."
(defcustom message-cite-prefix-regexp
(if (string-match "[[:digit:]]" "1") ;; support POSIX?
- "\\([ \t]*[-_.[:word:]]+>+\\|[ \t]*[]>»|:}+]\\)+"
+ "\\([ \t]*[-_.[:word:]]+>+\\|[ \t]*[]>»|:}+]\\)+"
;; ?-, ?_ or ?. MUST NOT be in syntax entry w.
"\\([ \t]*\\(\\w\\|[-_.]\\)+>+\\|[ \t]*[]>»|:}+]\\)+")
"*Regexp matching the longest possible citation prefix on a line."
`use', always use the value."
:group 'message-interface
:type '(choice (const :tag "ignore" nil)
+ (const :tag "use & query" t)
+ (const use)
+ (const ask)))
+
+(defcustom message-use-mail-followup-to 'use
+ "*Specifies what to do with Mail-Followup-To header.
+If nil, always ignore the header. If it is the symbol `ask', always
+query the user whether to use the value. If it is the symbol `use',
+always use the value."
+ :group 'message-interface
+ :type '(choice (const :tag "ignore" nil)
(const use)
(const ask)))
+(defcustom message-subscribed-address-functions nil
+ "*Specifies functions for determining list subscription.
+If nil, do not attempt to determine list subscribtion with functions.
+If non-nil, this variable contains a list of functions which return
+regular expressions to match lists. These functions can be used in
+conjunction with `message-subscribed-regexps' and
+`message-subscribed-addresses'."
+ :group 'message-interface
+ :type '(repeat sexp))
+
+(defcustom message-subscribed-address-file nil
+ "*A file containing addresses the user is subscribed to.
+If nil, do not look at any files to determine list subscriptions. If
+non-nil, each line of this file should be a mailing list address."
+ :group 'message-interface
+ :type 'string)
+
+(defcustom message-subscribed-addresses nil
+ "*Specifies a list of addresses the user is subscribed to.
+If nil, do not use any predefined list subscriptions. This list of
+addresses can be used in conjuction with
+`message-subscribed-address-functions' and `message-subscribed-regexps'."
+ :group 'message-interface
+ :type '(repeat string))
+
+(defcustom message-subscribed-regexps nil
+ "*Specifies a list of addresses the user is subscribed to.
+If nil, do not use any predefined list subscriptions. This list of
+regular expressions can be used in conjuction with
+`message-subscribed-address-functions' and `message-subscribed-addresses'."
+ :group 'message-interface
+ :type '(repeat regexp))
+
+(defcustom message-allow-no-recipients 'ask
+ "Specifies what to do when there are no recipients other than Gcc/Fcc.
+If it is the symbol `always', the posting is allowed. If it is the
+symbol `never', the posting is not allowed. If it is the symbol
+`ask', you are prompted."
+ :group 'message-interface
+ :type '(choice (const always)
+ (const never)
+ (const ask)))
+
(defcustom message-sendmail-f-is-evil nil
"*Non-nil means don't add \"-f username\" to the sendmail command line.
Doing so would be even more evil than leaving it out."
;;;###autoload
(defcustom message-citation-line-function 'message-insert-citation-line
- "*Function called to insert the \"Whomever writes:\" line."
+ "*Function called to insert the \"Whomever writes:\" line.
+
+Note that Gnus provides a feature where the reader can click on
+`writes:' to hide the cited text. If you change this line too much,
+people who read your message will have to change their Gnus
+configuration. See the variable `gnus-cite-attribution-suffix'."
:type 'function
:group 'message-insertion)
;;;###autoload
(defcustom message-yank-prefix "> "
"*Prefix inserted on the lines of yanked messages.
-Fix `message-cite-prefix-regexp' if it is set to an abnormal value."
+Fix `message-cite-prefix-regexp' if it is set to an abnormal value.
+See also `message-yank-cited-prefix'."
+ :type 'string
+ :group 'message-insertion)
+
+(defcustom message-yank-cited-prefix ">"
+ "*Prefix inserted on cited or empty lines of yanked messages.
+Fix `message-cite-prefix-regexp' if it is set to an abnormal value.
+See also `message-yank-prefix'."
:type 'string
:group 'message-insertion)
(defcustom message-dont-reply-to-names
(and (boundp 'rmail-dont-reply-to-names) rmail-dont-reply-to-names)
- "*A regexp specifying names to prune when doing wide replies.
-A value of nil means exclude your own name only."
+ "*A regexp specifying addresses to prune when doing wide replies.
+A value of nil means exclude your own user name only."
:version "21.1"
:group 'message
:type '(choice (const :tag "Yourself" nil)
table)
"Syntax table used while in Message mode.")
-(defvar message-mode-abbrev-table text-mode-abbrev-table
- "Abbrev table used in Message mode buffers.
-Defaults to `text-mode-abbrev-table'.")
-
(defface message-header-to-face
'((((class color)
(background dark))
:version "21.1"
:group 'message)
+(defcustom message-wide-reply-confirm-recipients nil
+ "Whether to confirm a wide reply to multiple email recipients.
+If this variable is nil, don't ask whether to reply to all recipients.
+If this variable is non-nil, pose the question \"Reply to all
+recipients?\" before a wide reply to multiple recipients. If the user
+answers yes, reply to all recipients as usual. If the user answers
+no, only reply back to the author."
+ :group 'message-headers
+ :type 'boolean)
+
+(defcustom message-insert-canlock t
+ "Whether to insert a Cancel-Lock header in news postings."
+ :group 'message-headers
+ :type 'boolean)
+
;;; Internal variables.
(defvar message-sending-message "Sending...")
(defvar message-options nil
"Some saved answers when sending message.")
+(defvar message-send-mail-real-function nil
+ "Internal send mail function.")
+
+(defvar message-bogus-system-names "^localhost\\."
+ "The regexp of bogus system names.")
+
(eval-and-compile
(autoload 'message-setup-toolbar "messagexmas")
(autoload 'mh-new-draft-name "mh-comp")
(autoload 'gnus-alive-p "gnus-util")
(autoload 'gnus-server-string "gnus")
(autoload 'gnus-group-name-charset "gnus-group")
+ (autoload 'gnus-group-name-decode "gnus-group")
+ (autoload 'gnus-groups-from-server "gnus")
(autoload 'rmail-output "rmailout"))
\f
(defun message-unquote-tokens (elems)
"Remove double quotes (\") from strings in list ELEMS."
(mapcar (lambda (item)
- (while (string-match "^\\(.*\\)\"\\(.*\\)$" item)
- (setq item (concat (match-string 1 item)
- (match-string 2 item))))
- item)
- elems))
+ (while (string-match "^\\(.*\\)\"\\(.*\\)$" item)
+ (setq item (concat (match-string 1 item)
+ (match-string 2 item))))
+ item)
+ elems))
(defun message-tokenize-header (header &optional separator)
"Split HEADER into a list of header elements.
((and (eq (char-after) ?\))
(not quoted))
(setq paren nil))))
- (nreverse elems)))))
+ (nreverse elems)))))
(defun message-mail-file-mbox-p (file)
"Say whether FILE looks like a Unix mbox file."
gnus-list-identifiers
(mapconcat 'identity gnus-list-identifiers " *\\|"))))
(if (string-match (concat "\\(\\(\\(Re: +\\)?\\(" regexp
- " *\\)\\)+\\(Re: +\\)?\\)") subject)
+ " *\\)\\)+\\(Re: +\\)?\\)") subject)
(concat (substring subject 0 (match-beginning 1))
(or (match-string 3 subject)
(match-string 5 subject))
(define-key message-mode-map "\C-c\C-f\C-n" 'message-goto-newsgroups)
(define-key message-mode-map "\C-c\C-f\C-d" 'message-goto-distribution)
(define-key message-mode-map "\C-c\C-f\C-f" 'message-goto-followup-to)
+ (define-key message-mode-map "\C-c\C-f\C-m" 'message-goto-mail-followup-to)
(define-key message-mode-map "\C-c\C-f\C-k" 'message-goto-keywords)
(define-key message-mode-map "\C-c\C-f\C-u" 'message-goto-summary)
+ (define-key message-mode-map "\C-c\C-f\C-i" 'message-insert-or-toggle-importance)
(define-key message-mode-map "\C-c\C-b" 'message-goto-body)
(define-key message-mode-map "\C-c\C-i" 'message-goto-signature)
(define-key message-mode-map "\C-c\C-s" 'message-send)
(define-key message-mode-map "\C-c\C-k" 'message-kill-buffer)
(define-key message-mode-map "\C-c\C-d" 'message-dont-send)
+ (define-key message-mode-map "\C-c\n" 'gnus-delay-article)
(define-key message-mode-map "\C-c\C-e" 'message-elide-region)
(define-key message-mode-map "\C-c\C-v" 'message-delete-not-region)
;;(define-key message-mode-map "\M-q" 'message-fill-paragraph)
(define-key message-mode-map "\C-c\C-a" 'mml-attach-file)
-
+
+ (define-key message-mode-map "\C-a" 'message-beginning-of-line)
(define-key message-mode-map "\t" 'message-tab)
(define-key message-mode-map "\M-;" 'comment-region))
(easy-menu-define
- message-mode-menu message-mode-map "Message Menu."
- `("Message"
- ["Sort Headers" message-sort-headers t]
- ["Yank Original" message-yank-original t]
- ["Fill Yanked Message" message-fill-yanked-message t]
- ["Insert Signature" message-insert-signature t]
- ["Caesar (rot13) Message" message-caesar-buffer-body t]
- ["Caesar (rot13) Region" message-caesar-region (mark t)]
- ["Elide Region" message-elide-region (mark t)]
- ["Delete Outside Region" message-delete-not-region (mark t)]
- ["Kill To Signature" message-kill-to-signature t]
- ["Newline and Reformat" message-newline-and-reformat t]
- ["Rename buffer" message-rename-buffer t]
- ["Spellcheck" ispell-message
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Spellcheck this message"))]
- ["Attach file as MIME" mml-attach-file
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Attach a file at point"))]
- "----"
- ["Send Message" message-send-and-exit
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Send this message"))]
- ["Abort Message" message-dont-send
- ,@(if (featurep 'xemacs) '(t)
- '(:help "File this draft message and exit"))]
- ["Kill Message" message-kill-buffer
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Delete this message without sending"))]))
+ message-mode-menu message-mode-map "Message Menu."
+ `("Message"
+ ["Sort Headers" message-sort-headers t]
+ ["Yank Original" message-yank-original t]
+ ["Fill Yanked Message" message-fill-yanked-message t]
+ ["Insert Signature" message-insert-signature t]
+ ["Caesar (rot13) Message" message-caesar-buffer-body t]
+ ["Caesar (rot13) Region" message-caesar-region (mark t)]
+ ["Elide Region" message-elide-region (mark t)]
+ ["Delete Outside Region" message-delete-not-region (mark t)]
+ ["Kill To Signature" message-kill-to-signature t]
+ ["Newline and Reformat" message-newline-and-reformat t]
+ ["Rename buffer" message-rename-buffer t]
+ ["Flag as important" message-insert-importance-high
+ ,@(if (featurep 'xemacs) '(t)
+ '(:help "Mark this message as important"))]
+ ["Flag as unimportant" message-insert-importance-low
+ ,@(if (featurep 'xemacs) '(t)
+ '(:help "Mark this message as unimportant"))]
+ ["Spellcheck" ispell-message
+ ,@(if (featurep 'xemacs) '(t)
+ '(:help "Spellcheck this message"))]
+ "----"
+ ["Send Message" message-send-and-exit
+ ,@(if (featurep 'xemacs) '(t)
+ '(:help "Send this message"))]
+ ["Postpone Message" message-dont-send
+ ,@(if (featurep 'xemacs) '(t)
+ '(:help "File this draft message and exit"))]
+ ["Send at Specific Time" gnus-delay-article
+ ,@(if (featurep 'xemacs) '(t)
+ '(:help "Ask, then arrange to send message at that time"))]
+ ["Kill Message" message-kill-buffer
+ ,@(if (featurep 'xemacs) '(t)
+ '(:help "Delete this message without sending"))]))
(easy-menu-define
- message-mode-field-menu message-mode-map ""
- '("Field"
- ["Fetch To" message-insert-to t]
- ["Fetch Newsgroups" message-insert-newsgroups t]
- "----"
- ["To" message-goto-to t]
- ["Subject" message-goto-subject t]
- ["Cc" message-goto-cc t]
- ["Reply-To" message-goto-reply-to t]
- ["Summary" message-goto-summary t]
- ["Keywords" message-goto-keywords t]
- ["Newsgroups" message-goto-newsgroups t]
- ["Followup-To" message-goto-followup-to t]
- ["Distribution" message-goto-distribution t]
- ["Body" message-goto-body t]
- ["Signature" message-goto-signature t]))
+ message-mode-field-menu message-mode-map ""
+ '("Field"
+ ["Fetch To" message-insert-to t]
+ ["Fetch Newsgroups" message-insert-newsgroups t]
+ "----"
+ ["To" message-goto-to t]
+ ["Subject" message-goto-subject t]
+ ["Cc" message-goto-cc t]
+ ["Reply-To" message-goto-reply-to t]
+ ["Summary" message-goto-summary t]
+ ["Keywords" message-goto-keywords t]
+ ["Newsgroups" message-goto-newsgroups t]
+ ["Followup-To" message-goto-followup-to t]
+ ["Mail-Followup-To" message-goto-mail-followup-to t]
+ ["Distribution" message-goto-distribution t]
+ ["Body" message-goto-body t]
+ ["Signature" message-goto-signature t]))
(defvar message-tool-bar-map nil)
(defvar facemenu-add-face-function)
(defvar facemenu-remove-face-function))
+;;; Forbidden properties
+;;
+;; We use `after-change-functions' to keep special text properties
+;; that interfer with the normal function of message mode out of the
+;; buffer.
+
+(defcustom message-strip-special-text-properties t
+ "Strip special properties from the message buffer.
+
+Emacs has a number of special text properties which can break message
+composing in various ways. If this option is set, message will strip
+these properties from the message composition buffer. However, some
+packages requires these properties to be present in order to work.
+If you use one of these packages, turn this option off, and hope the
+message composition doesn't break too bad."
+ :group 'message-various
+ :type 'boolean)
+
+(defconst message-forbidden-properties
+ ;; No reason this should be clutter up customize. We make it a
+ ;; property list (rather than a list of property symbols), to be
+ ;; directly useful for `remove-text-properties'.
+ '(field nil read-only nil intangible nil invisible nil
+ mouse-face nil modification-hooks nil insert-in-front-hooks nil
+ insert-behind-hooks nil point-entered nil point-left nil)
+ ;; Other special properties:
+ ;; category, face, display: probably doesn't do any harm.
+ ;; fontified: is used by font-lock.
+ ;; syntax-table, local-map: I dunno.
+ ;; We need to add XEmacs names to the list.
+ "Property list of with properties.forbidden in message buffers.
+The values of the properties are ignored, only the property names are used.")
+
+(defun message-tamago-not-in-use-p (pos)
+ "Return t when tamago version 4 is not in use at the cursor position.
+Tamago version 4 is a popular input method for writing Japanese text.
+It uses the properties `intangible', `invisible', `modification-hooks'
+and `read-only' when translating ascii or kana text to kanji text.
+These properties are essential to work, so we should never strip them."
+ (not (and (boundp 'egg-modefull-mode)
+ (symbol-value 'egg-modefull-mode)
+ (or (memq (get-text-property pos 'intangible)
+ '(its-part-1 its-part-2))
+ (get-text-property pos 'egg-end)
+ (get-text-property pos 'egg-lang)
+ (get-text-property pos 'egg-start)))))
+
+(defun message-strip-forbidden-properties (begin end &optional old-length)
+ "Strip forbidden properties between BEGIN and END, ignoring the third arg.
+This function is intended to be called from `after-change-functions'.
+See also `message-forbidden-properties'."
+ (when (and message-strip-special-text-properties
+ (message-tamago-not-in-use-p begin))
+ (remove-text-properties begin end message-forbidden-properties)))
+
;;;###autoload
-(defun message-mode ()
+(define-derived-mode message-mode text-mode "Message"
"Major mode for editing mail and news to be sent.
Like Text Mode but with these additional commands:\\<message-mode-map>
C-c C-s `message-send' (send the message) C-c C-c `message-send-and-exit'
C-c C-f C-u move to Summary C-c C-f C-n move to Newsgroups
C-c C-f C-k move to Keywords C-c C-f C-d move to Distribution
C-c C-f C-f move to Followup-To
+ C-c C-f C-m move to Mail-Followup-To
C-c C-t `message-insert-to' (add a To header to a news followup)
C-c C-n `message-insert-newsgroups' (add a Newsgroup header to a news reply)
C-c C-b `message-goto-body' (move to beginning of message text).
C-c C-z `message-kill-to-signature' (kill the text up to the signature).
C-c C-r `message-caesar-buffer-body' (rot13 the message body).
C-c C-a `mml-attach-file' (attach a file as MIME).
+C-c C-u `message-insert-or-toggle-importance' (insert or cycle importance)
M-RET `message-newline-and-reformat' (break the line and reformat)."
- (interactive)
- (if (local-variable-p 'mml-buffer-list (current-buffer))
- (mml-destroy-buffers))
- (kill-all-local-variables)
(set (make-local-variable 'message-reply-buffer) nil)
(make-local-variable 'message-send-actions)
(make-local-variable 'message-exit-actions)
(make-local-variable 'message-kill-actions)
(make-local-variable 'message-postpone-actions)
(make-local-variable 'message-draft-article)
- (make-local-hook 'kill-buffer-hook)
- (set-syntax-table message-mode-syntax-table)
- (use-local-map message-mode-map)
- (setq local-abbrev-table message-mode-abbrev-table)
- (setq major-mode 'message-mode)
- (setq mode-name "Message")
(setq buffer-offer-save t)
- (make-local-variable 'facemenu-add-face-function)
- (make-local-variable 'facemenu-remove-face-function)
- (setq facemenu-add-face-function
- (lambda (face end)
- (let ((face-fun (cdr (assq face message-face-alist))))
- (if face-fun
- (funcall face-fun (point) end)
- (error "Face %s not configured for %s mode" face mode-name)))
- "")
- facemenu-remove-face-function t)
- (make-local-variable 'message-reply-headers)
- (setq message-reply-headers nil)
+ (set (make-local-variable 'facemenu-add-face-function)
+ (lambda (face end)
+ (let ((face-fun (cdr (assq face message-face-alist))))
+ (if face-fun
+ (funcall face-fun (point) end)
+ (error "Face %s not configured for %s mode" face mode-name)))
+ ""))
+ (set (make-local-variable 'facemenu-remove-face-function) t)
+ (set (make-local-variable 'message-reply-headers) nil)
(make-local-variable 'message-newsreader)
(make-local-variable 'message-mailer)
(make-local-variable 'message-post-method)
(set (make-local-variable 'tool-bar-map) (message-tool-bar-map))))
(easy-menu-add message-mode-menu message-mode-map)
(easy-menu-add message-mode-field-menu message-mode-map)
+ ;; make-local-hook is harmless though obsolete in Emacs 21.
+ ;; Emacs 20 and XEmacs need make-local-hook.
+ (make-local-hook 'after-change-functions)
+ ;; Mmmm... Forbidden properties...
+ (add-hook 'after-change-functions 'message-strip-forbidden-properties
+ nil 'local)
;; Allow mail alias things.
(when (eq message-mail-alias-type 'abbrev)
(if (fboundp 'mail-abbrevs-setup)
(mail-aliases-setup)))
(message-set-auto-save-file-name)
(mm-enable-multibyte)
- (make-local-variable 'indent-tabs-mode) ;Turn off tabs for indentation.
- (setq indent-tabs-mode nil)
- (mml-mode)
- (run-hooks 'text-mode-hook 'message-mode-hook))
+ (set (make-local-variable 'indent-tabs-mode) nil) ;No tabs for indentation.
+ (mml-mode))
(defun message-setup-fill-variables ()
"Setup message fill variables."
- (set (make-local-variable 'fill-paragraph-function)
+ (set (make-local-variable 'fill-paragraph-function)
'message-fill-paragraph)
(make-local-variable 'paragraph-separate)
(make-local-variable 'paragraph-start)
(unless (boundp 'adaptive-fill-first-line-regexp)
(setq adaptive-fill-first-line-regexp nil))
(make-local-variable 'adaptive-fill-first-line-regexp)
- (make-local-variable 'auto-fill-inhibit-regexp)
(let ((quote-prefix-regexp
;; User should change message-cite-prefix-regexp if
;; message-yank-prefix is set to an abnormal value.
- (concat "\\(" message-cite-prefix-regexp "\\)[ \t]*")))
+ (concat "\\(" message-cite-prefix-regexp "\\)[ \t]*")))
(setq paragraph-start
- (concat
- (regexp-quote mail-header-separator) "$\\|"
- "[ \t]*$\\|" ; blank lines
- "-- $\\|" ; signature delimiter
- "---+$\\|" ; delimiters for forwarded messages
- page-delimiter "$\\|" ; spoiler warnings
- ".*wrote:$\\|" ; attribution lines
- quote-prefix-regexp "$")) ; empty lines in quoted text
+ (concat
+ (regexp-quote mail-header-separator) "$\\|"
+ "[ \t]*$\\|" ; blank lines
+ "-- $\\|" ; signature delimiter
+ "---+$\\|" ; delimiters for forwarded messages
+ page-delimiter "$\\|" ; spoiler warnings
+ ".*wrote:$\\|" ; attribution lines
+ quote-prefix-regexp "$")) ; empty lines in quoted text
(setq paragraph-separate paragraph-start)
(setq adaptive-fill-regexp
- (concat quote-prefix-regexp "\\|" adaptive-fill-regexp))
+ (concat quote-prefix-regexp "\\|" adaptive-fill-regexp))
(setq adaptive-fill-first-line-regexp
- (concat quote-prefix-regexp "\\|"
- adaptive-fill-first-line-regexp))
- (setq auto-fill-inhibit-regexp "^[A-Z][^: \n\t]+:")))
+ (concat quote-prefix-regexp "\\|"
+ adaptive-fill-first-line-regexp)))
+ (make-local-variable 'auto-fill-inhibit-regexp)
+ ;;(setq auto-fill-inhibit-regexp "^[A-Z][^: \n\t]+:")
+ (setq auto-fill-inhibit-regexp nil)
+ (make-local-variable 'normal-auto-fill-function)
+ (setq normal-auto-fill-function 'message-do-auto-fill)
+ ;; KLUDGE: auto fill might already be turned on in `text-mode-hook'.
+ ;; In that case, ensure that it uses the right function. The real
+ ;; solution would be not to use `define-derived-mode', and run
+ ;; `text-mode-hook' ourself at the end of the mode.
+ ;; -- Per Abrahamsen <abraham@dina.kvl.dk> Date: 2001-10-19.
+ (when auto-fill-function
+ (setq auto-fill-function normal-auto-fill-function)))
\f
(interactive)
(message-position-on-field "Followup-To" "Newsgroups"))
+(defun message-goto-mail-followup-to ()
+ "Move point to the Mail-Followup-To header."
+ (interactive)
+ (message-position-on-field "Mail-Followup-To" "From"))
+
(defun message-goto-keywords ()
"Move point to the Keywords header."
(interactive)
(expand-abbrev))
(goto-char (point-min))
(or (search-forward (concat "\n" mail-header-separator "\n") nil t)
- (search-forward "\n\n" nil t)))
+ (search-forward-regexp "[^:]+:\\([^\n]\\|\n[ \t]\\)+\n\n" nil t)))
(defun message-goto-eoh ()
"Move point to the end of the headers."
(defun message-delete-not-region (beg end)
"Delete everything in the body of the current message outside of the region."
(interactive "r")
- (save-excursion
- (goto-char end)
- (delete-region (point) (if (not (message-goto-signature))
- (point)
- (forward-line -2)
- (point)))
- (insert "\n")
- (goto-char beg)
- (delete-region beg (progn (message-goto-body)
- (forward-line 2)
- (point))))
+ (let (citeprefix)
+ (save-excursion
+ (goto-char beg)
+ ;; snarf citation prefix, if appropriate
+ (unless (eq (point) (progn (beginning-of-line) (point)))
+ (when (looking-at message-cite-prefix-regexp)
+ (setq citeprefix (match-string 0))))
+ (goto-char end)
+ (delete-region (point) (if (not (message-goto-signature))
+ (point)
+ (forward-line -2)
+ (point)))
+ (insert "\n")
+ (goto-char beg)
+ (delete-region beg (progn (message-goto-body)
+ (forward-line 2)
+ (point)))
+ (when citeprefix
+ (insert citeprefix))))
(when (message-goto-signature)
(forward-line -2)))
(if not-break
(while (and (not (eobp))
(not (looking-at message-cite-prefix-regexp))
- (looking-at paragraph-start))
+ (looking-at paragraph-start))
(forward-line 1)))
;; Find the prefix
(when (looking-at message-cite-prefix-regexp)
(insert quoted leading-space)))
(if quoted
(let* ((adaptive-fill-regexp
- (regexp-quote (concat quoted leading-space)))
+ (regexp-quote (concat quoted leading-space)))
(adaptive-fill-first-line-regexp
adaptive-fill-regexp ))
(fill-paragraph arg))
(defun message-fill-paragraph (&optional arg)
"Like `fill-paragraph'."
(interactive (list (if current-prefix-arg 'full)))
- (message-newline-and-reformat arg t)
- t)
+ (if (and (boundp 'filladapt-mode) filladapt-mode)
+ nil
+ (message-newline-and-reformat arg t)
+ t))
+
+;; Is it better to use `mail-header-end'?
+(defun message-point-in-header-p ()
+ "Return t if point is in the header."
+ (save-excursion
+ (let ((p (point)))
+ (goto-char (point-min))
+ (not (re-search-forward
+ (concat "^" (regexp-quote mail-header-separator) "\n")
+ p t)))))
+
+(defun message-do-auto-fill ()
+ "Like `do-auto-fill', but don't fill in message header."
+ (unless (message-point-in-header-p)
+ (do-auto-fill)))
(defun message-insert-signature (&optional force)
"Insert a signature. See documentation for variable `message-signature'."
(goto-char (point-max))
(or (bolp) (insert "\n")))))
+(defun message-insert-importance-high ()
+ "Insert header to mark message as important."
+ (interactive)
+ (save-excursion
+ (message-remove-header "Importance")
+ (message-goto-eoh)
+ (insert "Importance: high\n")))
+
+(defun message-insert-importance-low ()
+ "Insert header to mark message as unimportant."
+ (interactive)
+ (save-excursion
+ (message-remove-header "Importance")
+ (message-goto-eoh)
+ (insert "Importance: low\n")))
+
+(defun message-insert-or-toggle-importance ()
+ "Insert a \"Importance: high\" header, or cycle through the header values.
+The three allowed values according to RFC 1327 are `high', `normal'
+and `low'."
+ (interactive)
+ (save-excursion
+ (let ((valid '("high" "normal" "low"))
+ (new "high")
+ cur)
+ (when (setq cur (message-fetch-field "Importance"))
+ (message-remove-header "Importance")
+ (setq new (cond ((string= cur "high")
+ "low")
+ ((string= cur "low")
+ "normal")
+ (t
+ "high"))))
+ (message-goto-eoh)
+ (insert (format "Importance: %s\n" new)))))
+
(defun message-elide-region (b e)
"Elide the text in the region.
An ellipsis (from `message-elide-ellipsis') will be inserted where the
(prefix-numeric-value current-prefix-arg))))
(setq n (if (numberp n) (mod n 26) 13)) ;canonize N
- (unless (or (zerop n) ; no action needed for a rot of 0
+ (unless (or (zerop n) ; no action needed for a rot of 0
(= b e)) ; no region to rotate
;; We build the table, if necessary.
(when (or (not message-caesar-translation-table)
(save-excursion
(save-restriction
(when (message-goto-body)
- (narrow-to-region (point) (point-max)))
+ (narrow-to-region (point) (point-max)))
(shell-command-on-region
(point-min) (point-max) program nil t))))
(save-excursion
(goto-char start)
(while (< (point) (mark t))
- (insert message-yank-prefix)
- (forward-line 1))))
+ (if (or (looking-at ">") (looking-at "^$"))
+ (insert message-yank-cited-prefix)
+ (insert message-yank-prefix))
+ (forward-line 1))))
(goto-char start)))
(defun message-yank-original (&optional arg)
(insert "\n"))
(funcall message-citation-line-function))))
-(eval-when-compile (defvar mail-citation-hook)) ;Compiler directive
+(eval-when-compile (defvar mail-citation-hook)) ;Compiler directive
(defun message-cite-original ()
"Cite function in the standard Message manner."
(if (and (boundp 'mail-citation-hook)
(interactive)
(when (or (not (buffer-modified-p))
(yes-or-no-p "Message modified; kill anyway? "))
- (let ((actions message-kill-actions))
+ (let ((actions message-kill-actions)
+ (draft-article message-draft-article)
+ (auto-save-file-name buffer-auto-save-file-name)
+ (file-name buffer-file-name)
+ (modified (buffer-modified-p)))
(setq buffer-file-name nil)
(kill-buffer (current-buffer))
+ (when (and (or (and auto-save-file-name
+ (file-exists-p auto-save-file-name))
+ (and file-name
+ (file-exists-p file-name)))
+ (yes-or-no-p (format "Remove the backup file%s? "
+ (if modified " too" ""))))
+ (ignore-errors
+ (delete-file auto-save-file-name))
+ (let ((message-draft-article draft-article))
+ (message-disassociate-draft)))
(message-do-actions actions))))
(defun message-bury (buffer)
(message message-sending-message)
(let ((alist message-send-method-alist)
(success t)
- elem sent
+ elem sent dont-barf-on-no-method
(message-options message-options))
(message-options-set-recipient)
(while (and success
(format
"Already sent message via %s; resend? "
(car elem)))
- (error "Denied posting -- multiple copies.")))
+ (error "Denied posting -- multiple copies")))
(setq success (funcall (caddr elem) arg)))
(setq sent t))))
- (unless (or sent (not success))
+ (unless (or sent
+ (not success)
+ (let ((fcc (message-fetch-field "Fcc"))
+ (gcc (message-fetch-field "Gcc")))
+ (when (or fcc gcc)
+ (or (eq message-allow-no-recipients 'always)
+ (and (not (eq message-allow-no-recipients 'never))
+ (setq dont-barf-on-no-method
+ (gnus-y-or-n-p
+ (format "No receiver, perform %s anyway? "
+ (cond ((and fcc gcc) "Fcc and Gcc")
+ (fcc "Fcc")
+ (t "Gcc"))))))))))
(error "No methods specified to send by"))
- (when (and success sent)
+ (when (or dont-barf-on-no-method
+ (and success sent))
(message-do-fcc)
(save-excursion
(run-hooks 'message-sent-hook))
(insert "Mime-Version: 1.0\n")
(setq header (buffer-substring (point-min) (point-max))))
(goto-char (point-max))
- (insert (format "Content-Type: message/partial; id=\"%s\"; number=%d; total=%d\n"
+ (insert (format "Content-Type: message/partial; id=\"%s\"; number=%d; total=%d\n\n"
id n total))
+ (forward-char -1)
(let ((mail-header-separator ""))
(when (memq 'Message-ID message-required-mail-headers)
(insert "Message-ID: " (message-make-message-id) "\n"))
(when (memq 'Lines message-required-mail-headers)
- (let ((mail-header-separator ""))
- (insert "Lines: " (message-make-lines) "\n")))
+ (insert "Lines: " (message-make-lines) "\n"))
(message-goto-subject)
(end-of-line)
(insert (format " (%d/%d)" n total))
- (goto-char (point-max))
- (insert "\n")
(widen)
(mm-with-unibyte-current-buffer
- (funcall message-send-mail-function)))
+ (funcall (or message-send-mail-real-function
+ message-send-mail-function))))
(setq n (+ n 1))
(setq p (pop plist))
(erase-buffer)))
(message-posting-charset
(if (fboundp 'gnus-setup-posting-charset)
(gnus-setup-posting-charset nil)
- message-posting-charset)))
+ message-posting-charset))
+ (headers message-required-mail-headers))
(save-restriction
(message-narrow-to-headers)
+ ;; Generate the Mail-Followup-To header if the header is not there...
+ (if (and (or message-subscribed-regexps
+ message-subscribed-addresses
+ message-subscribed-address-file
+ message-subscribed-address-functions)
+ (not (mail-fetch-field "mail-followup-to")))
+ (setq headers
+ (cons
+ (cons "Mail-Followup-To" (message-make-mft))
+ message-required-mail-headers))
+ ;; otherwise, delete the MFT header if the field is empty
+ (when (equal "" (mail-fetch-field "mail-followup-to"))
+ (message-remove-header "^Mail-Followup-To:")))
;; Insert some headers.
(let ((message-deletable-headers
(if news nil message-deletable-headers)))
- (message-generate-headers message-required-mail-headers))
+ (message-generate-headers headers))
;; Let the user do all of the above.
(run-hooks 'message-header-hook))
(unwind-protect
(not (y-or-n-p "Message exceeds message-send-mail-partially-limit, send in parts? ")))
(mm-with-unibyte-current-buffer
(message "Sending via mail...")
- (funcall message-send-mail-function))
+ (funcall (or message-send-mail-real-function
+ message-send-mail-function)))
(message-send-mail-partially)))
(kill-buffer tembuf))
(set-buffer mailbuf)
;; qmail-inject doesn't say anything on it's stdout/stderr,
;; we have to look at the retval instead
(0 nil)
- (1 (error "qmail-inject reported permanent failure"))
+ (100 (error "qmail-inject reported permanent failure"))
(111 (error "qmail-inject reported transient failure"))
;; should never happen
(t (error "qmail-inject reported unknown failure"))))
;; Pass it on to mh.
(mh-send-letter)))
+(defun message-canlock-generate ()
+ "Return a string that is non-trival to guess.
+Do not use this for anything important, it is cryptographically weak."
+ (sha1 (concat (message-unique-id)
+ (format "%x%x%x" (random) (random t) (random))
+ (prin1-to-string (recent-keys))
+ (prin1-to-string (garbage-collect)))))
+
+(defun message-canlock-password ()
+ "The password used by message for cancel locks.
+This is the value of `canlock-password', if that option is non-nil.
+Otherwise, generate and save a value for `canlock-password' first."
+ (unless canlock-password
+ (customize-save-variable 'canlock-password (message-canlock-generate)))
+ canlock-password)
+
+(defun message-insert-canlock ()
+ (when message-insert-canlock
+ (message-canlock-password)
+ (canlock-insert-header)))
+
(defun message-send-news (&optional arg)
(let* ((tembuf (message-generate-new-buffer-clone-locals " *message temp*"))
(case-fold-search nil)
(method (if (message-functionp message-post-method)
(funcall message-post-method arg)
message-post-method))
- (group-name-charset (gnus-group-name-charset method ""))
+ (newsgroups-field (save-restriction
+ (message-narrow-to-headers-or-head)
+ (message-fetch-field "Newsgroups")))
+ (followup-field (save-restriction
+ (message-narrow-to-headers-or-head)
+ (message-fetch-field "Followup-To")))
+ ;; BUG: We really need to get the charset for each name in the
+ ;; Newsgroups and Followup-To lines to allow crossposting
+ ;; between group namess with incompatible character sets.
+ ;; -- Per Abrahamsen <abraham@dina.kvl.dk> 2001-10-08.
+ (group-field-charset
+ (gnus-group-name-charset method newsgroups-field))
+ (followup-field-charset
+ (gnus-group-name-charset method (or followup-field "")))
(rfc2047-header-encoding-alist
- (if group-name-charset
- (cons (cons "Newsgroups" group-name-charset)
- rfc2047-header-encoding-alist)
- rfc2047-header-encoding-alist))
+ (append (when group-field-charset
+ (list (cons "Newsgroups" group-field-charset)))
+ (when followup-field-charset
+ (list (cons "Followup-To" followup-field-charset)))
+ rfc2047-header-encoding-alist))
(messbuf (current-buffer))
(message-syntax-checks
- (if arg
+ (if (and arg
+ (listp message-syntax-checks))
(cons '(existing-newsgroups . disabled)
message-syntax-checks)
message-syntax-checks))
(message-this-is-news t)
- (message-posting-charset (gnus-setup-posting-charset
- (save-restriction
- (message-narrow-to-headers-or-head)
- (message-fetch-field "Newsgroups"))))
+ (message-posting-charset
+ (gnus-setup-posting-charset newsgroups-field))
result)
(if (not (message-check-news-body-syntax))
nil
(message-narrow-to-headers)
;; Insert some headers.
(message-generate-headers message-required-news-headers)
+ (message-insert-canlock)
;; Let the user do all of the above.
(run-hooks 'message-header-hook))
- (when group-name-charset
+ ;; Note: This check will be disabled by the ".*" default value for
+ ;; gnus-group-name-charset-group-alist. -- Pa 2001-10-07.
+ (when (and group-field-charset
+ (listp message-syntax-checks))
(setq message-syntax-checks
(cons '(valid-newsgroups . disabled)
message-syntax-checks)))
(message-cleanup-headers)
- (if (not (message-check-news-syntax))
+ (if (not (let ((message-post-method method))
+ (message-check-news-syntax)))
nil
(unwind-protect
(save-excursion
(if followup-to
(concat newsgroups "," followup-to)
newsgroups)))
- (hashtb (and (boundp 'gnus-active-hashtb)
- gnus-active-hashtb))
+ (post-method (if (message-functionp message-post-method)
+ (funcall message-post-method)
+ message-post-method))
+ ;; KLUDGE to handle nnvirtual groups. Doing this right
+ ;; would probably involve a new nnoo function.
+ ;; -- Per Abrahamsen <abraham@dina.kvl.dk>, 2001-10-17.
+ (method (if (and (consp post-method)
+ (eq (car post-method) 'nnvirtual)
+ gnus-message-group-art)
+ (let ((group (car (nnvirtual-find-group-art
+ (car gnus-message-group-art)
+ (cdr gnus-message-group-art)))))
+ (gnus-find-method-for-group group))
+ post-method))
+ (known-groups
+ (mapcar (lambda (n)
+ (gnus-group-name-decode
+ (gnus-group-real-name n)
+ (gnus-group-name-charset method n)))
+ (gnus-groups-from-server method)))
errors)
(while groups
- (when (and (not (boundp (intern (car groups) hashtb)))
- (not (equal (car groups) "poster")))
+ (unless (or (equal (car groups) "poster")
+ (member (car groups) known-groups))
(push (car groups) errors))
(pop groups))
(cond
;; Gnus is not running.
- ((or (not hashtb)
+ ((or (not (and (boundp 'gnus-active-hashtb)
+ gnus-active-hashtb))
(not (boundp 'gnus-read-active-file)))
t)
;; We don't have all the group names.
(if (= (length errors) 1) "this" "these")
(if (= (length errors) 1) "" "s")
(mapconcat 'identity errors ", ")))))))
- ;; Check the Newsgroups & Followup-To headers for syntax errors.
- (message-check 'valid-newsgroups
- (let ((case-fold-search t)
- (headers '("Newsgroups" "Followup-To"))
- header error)
- (while (and headers (not error))
- (when (setq header (mail-fetch-field (car headers)))
- (if (or
- (not
- (string-match
- "\\`\\([-+_&.a-zA-Z0-9]+\\)?\\(,[-+_&.a-zA-Z0-9]+\\)*\\'"
- header))
- (memq
- nil (mapcar
- (lambda (g)
- (not (string-match "\\.\\'\\|\\.\\." g)))
- (message-tokenize-header header ","))))
- (setq error t)))
- (unless error
- (pop headers)))
- (if (not error)
- t
- (y-or-n-p
- (format "The %s header looks odd: \"%s\". Really post? "
- (car headers) header)))))
- (message-check 'repeated-newsgroups
- (let ((case-fold-search t)
- (headers '("Newsgroups" "Followup-To"))
- header error groups group)
- (while (and headers
- (not error))
- (when (setq header (mail-fetch-field (pop headers)))
- (setq groups (message-tokenize-header header ","))
- (while (setq group (pop groups))
- (when (member group groups)
- (setq error group
- groups nil)))))
- (if (not error)
- t
- (y-or-n-p
- (format "Group %s is repeated in headers. Really post? " error)))))
- ;; Check the From header.
- (message-check 'from
- (let* ((case-fold-search t)
- (from (message-fetch-field "from"))
- ad)
- (cond
- ((not from)
- (message "There is no From line. Posting is denied.")
- nil)
- ((or (not (string-match
- "@[^\\.]*\\."
- (setq ad (nth 1 (mail-extract-address-components
- from))))) ;larsi@ifi
- (string-match "\\.\\." ad) ;larsi@ifi..uio
- (string-match "@\\." ad) ;larsi@.ifi.uio
- (string-match "\\.$" ad) ;larsi@ifi.uio.
- (not (string-match "^[^@]+@[^@]+$" ad)) ;larsi.ifi.uio
- (string-match "(.*).*(.*)" from)) ;(lars) (lars)
- (message
- "Denied posting -- the From looks strange: \"%s\"." from)
- nil)
- (t t))))))
+ ;; Check the Newsgroups & Followup-To headers for syntax errors.
+ (message-check 'valid-newsgroups
+ (let ((case-fold-search t)
+ (headers '("Newsgroups" "Followup-To"))
+ header error)
+ (while (and headers (not error))
+ (when (setq header (mail-fetch-field (car headers)))
+ (if (or
+ (not
+ (string-match
+ "\\`\\([-+_&.a-zA-Z0-9]+\\)?\\(,[-+_&.a-zA-Z0-9]+\\)*\\'"
+ header))
+ (memq
+ nil (mapcar
+ (lambda (g)
+ (not (string-match "\\.\\'\\|\\.\\." g)))
+ (message-tokenize-header header ","))))
+ (setq error t)))
+ (unless error
+ (pop headers)))
+ (if (not error)
+ t
+ (y-or-n-p
+ (format "The %s header looks odd: \"%s\". Really post? "
+ (car headers) header)))))
+ (message-check 'repeated-newsgroups
+ (let ((case-fold-search t)
+ (headers '("Newsgroups" "Followup-To"))
+ header error groups group)
+ (while (and headers
+ (not error))
+ (when (setq header (mail-fetch-field (pop headers)))
+ (setq groups (message-tokenize-header header ","))
+ (while (setq group (pop groups))
+ (when (member group groups)
+ (setq error group
+ groups nil)))))
+ (if (not error)
+ t
+ (y-or-n-p
+ (format "Group %s is repeated in headers. Really post? " error)))))
+ ;; Check the From header.
+ (message-check 'from
+ (let* ((case-fold-search t)
+ (from (message-fetch-field "from"))
+ ad)
+ (cond
+ ((not from)
+ (message "There is no From line. Posting is denied.")
+ nil)
+ ((or (not (string-match
+ "@[^\\.]*\\."
+ (setq ad (nth 1 (mail-extract-address-components
+ from))))) ;larsi@ifi
+ (string-match "\\.\\." ad) ;larsi@ifi..uio
+ (string-match "@\\." ad) ;larsi@.ifi.uio
+ (string-match "\\.$" ad) ;larsi@ifi.uio.
+ (not (string-match "^[^@]+@[^@]+$" ad)) ;larsi.ifi.uio
+ (string-match "(.*).*(.*)" from)) ;(lars) (lars)
+ (message
+ "Denied posting -- the From looks strange: \"%s\"." from)
+ nil)
+ ((let ((addresses (rfc822-addresses from)))
+ (while (and addresses
+ (not (eq (string-to-char (car addresses)) ?\()))
+ (setq addresses (cdr addresses)))
+ addresses)
+ (message
+ "Denied posting -- bad From address: \"%s\"." from)
+ nil)
+ (t t))))
+ ;; Check the Reply-To header.
+ (message-check 'reply-to
+ (let* ((case-fold-search t)
+ (reply-to (message-fetch-field "reply-to"))
+ ad)
+ (cond
+ ((not reply-to)
+ t)
+ ((string-match "," reply-to)
+ (y-or-n-p
+ (format "Multiple Reply-To addresses: \"%s\". Really post? "
+ reply-to)))
+ ((or (not (string-match
+ "@[^\\.]*\\."
+ (setq ad (nth 1 (mail-extract-address-components
+ reply-to))))) ;larsi@ifi
+ (string-match "\\.\\." ad) ;larsi@ifi..uio
+ (string-match "@\\." ad) ;larsi@.ifi.uio
+ (string-match "\\.$" ad) ;larsi@ifi.uio.
+ (not (string-match "^[^@]+@[^@]+$" ad)) ;larsi.ifi.uio
+ (string-match "(.*).*(.*)" reply-to)) ;(lars) (lars)
+ (y-or-n-p
+ (format
+ "The Reply-To looks strange: \"%s\". Really post? "
+ reply-to)))
+ (t t))))))
(defun message-check-news-body-syntax ()
(and
(concat "^" (regexp-quote mail-header-separator) "$"))
(forward-line 1)
(while (and
- (or (looking-at
+ (or (looking-at
"<#\\(/\\)?\\(multipart\\|part\\|external\\|mml\\)")
(let ((p (point)))
(end-of-line)
(concat "^" (regexp-quote mail-header-separator) "$"))
(while (not (eobp))
(when (not (looking-at "[ \t\n]"))
- (setq sum (logxor (ash sum 1) (if (natnump sum) 0 1)
- (char-after))))
+ (setq sum (logxor (ash sum 1) (if (natnump sum) 0 1)
+ (char-after))))
(forward-char 1)))
sum))
(buf (current-buffer))
list file)
(save-excursion
- (set-buffer (get-buffer-create " *message temp*"))
- (erase-buffer)
- (insert-buffer-substring buf)
(save-restriction
(message-narrow-to-headers)
- (while (setq file (message-fetch-field "fcc"))
- (push file list)
- (message-remove-header "fcc" nil t)))
- (message-encode-message-body)
- (save-restriction
- (message-narrow-to-headers)
- (let ((mail-parse-charset message-default-charset)
- (rfc2047-header-encoding-alist
- (cons '("Newsgroups" . default)
- rfc2047-header-encoding-alist)))
- (mail-encode-encoded-word-buffer)))
- (goto-char (point-min))
- (when (re-search-forward
- (concat "^" (regexp-quote mail-header-separator) "$")
- nil t)
- (replace-match "" t t ))
- ;; Process FCC operations.
- (while list
- (setq file (pop list))
- (if (string-match "^[ \t]*|[ \t]*\\(.*\\)[ \t]*$" file)
- ;; Pipe the article to the program in question.
- (call-process-region (point-min) (point-max) shell-file-name
- nil nil nil shell-command-switch
- (match-string 1 file))
- ;; Save the article.
- (setq file (expand-file-name file))
- (unless (file-exists-p (file-name-directory file))
- (make-directory (file-name-directory file) t))
- (if (and message-fcc-handler-function
- (not (eq message-fcc-handler-function 'rmail-output)))
- (funcall message-fcc-handler-function file)
- (if (and (file-readable-p file) (mail-file-babyl-p file))
- (rmail-output file 1 nil t)
- (let ((mail-use-rfc822 t))
- (rmail-output file 1 t t))))))
- (kill-buffer (current-buffer)))))
+ (setq file (message-fetch-field "fcc" t)))
+ (when file
+ (set-buffer (get-buffer-create " *message temp*"))
+ (erase-buffer)
+ (insert-buffer-substring buf)
+ (message-encode-message-body)
+ (save-restriction
+ (message-narrow-to-headers)
+ (while (setq file (message-fetch-field "fcc" t))
+ (push file list)
+ (message-remove-header "fcc" nil t))
+ (let ((mail-parse-charset message-default-charset)
+ (rfc2047-header-encoding-alist
+ (cons '("Newsgroups" . default)
+ rfc2047-header-encoding-alist)))
+ (mail-encode-encoded-word-buffer)))
+ (goto-char (point-min))
+ (when (re-search-forward
+ (concat "^" (regexp-quote mail-header-separator) "$")
+ nil t)
+ (replace-match "" t t ))
+ ;; Process FCC operations.
+ (while list
+ (setq file (pop list))
+ (if (string-match "^[ \t]*|[ \t]*\\(.*\\)[ \t]*$" file)
+ ;; Pipe the article to the program in question.
+ (call-process-region (point-min) (point-max) shell-file-name
+ nil nil nil shell-command-switch
+ (match-string 1 file))
+ ;; Save the article.
+ (setq file (expand-file-name file))
+ (unless (file-exists-p (file-name-directory file))
+ (make-directory (file-name-directory file) t))
+ (if (and message-fcc-handler-function
+ (not (eq message-fcc-handler-function 'rmail-output)))
+ (funcall message-fcc-handler-function file)
+ (if (and (file-readable-p file) (mail-file-babyl-p file))
+ (rmail-output file 1 nil t)
+ (let ((mail-use-rfc822 t))
+ (rmail-output file 1 t t))))))
+ (kill-buffer (current-buffer))))))
(defun message-output (filename)
"Append this article to Unix/babyl mail file FILENAME."
(point)))
(goto-char (point-min))
(while (re-search-forward "\n[ \t]+" nil t)
- (replace-match " " t t)) ;No line breaks (too confusing)
+ (replace-match " " t t)) ;No line breaks (too confusing)
(goto-char (point-min))
(while (re-search-forward "[ \t\n]*,[ \t\n]*\\|[ \t]+" nil t)
(replace-match "," t t))
(setq sign "-")
(setq zone (- zone)))
(concat
+ ;; The day name of the %a spec is locale-specific. Pfff.
+ (format "%s, " (capitalize (car (rassoc (nth 6 (decode-time now))
+ parse-time-weekdays))))
(format-time-string "%d" now)
;; The month name of the %b spec is locale-specific. Pfff.
(format " %s "
(let ((system-name (system-name))
(user-mail (message-user-mail-address)))
(cond
- ((string-match "[^.]\\.[^.]" system-name)
+ ((and (string-match "[^.]\\.[^.]" system-name)
+ (not (string-match message-bogus-system-names system-name)))
;; `system-name' returned the right result.
system-name)
;; Try `mail-host-address'.
(or mail-host-address
(message-make-fqdn)))
+(defun message-make-mft ()
+ "Return the Mail-Followup-To header."
+ (let* ((msg-recipients (message-options-get 'message-recipients))
+ (recipients
+ (mapcar 'mail-strip-quoted-names
+ (message-tokenize-header msg-recipients)))
+ (file-regexps
+ (if message-subscribed-address-file
+ (let (begin end item re)
+ (save-excursion
+ (with-temp-buffer
+ (insert-file-contents message-subscribed-address-file)
+ (while (not (eobp))
+ (setq begin (point))
+ (forward-line 1)
+ (setq end (point))
+ (if (bolp) (setq end (1- end)))
+ (setq item (regexp-quote (buffer-substring begin end)))
+ (if re (setq re (concat re "\\|" item))
+ (setq re (concat "\\`\\(" item))))
+ (and re (list (concat re "\\)\\'"))))))))
+ (mft-regexps (apply 'append message-subscribed-regexps
+ (mapcar 'regexp-quote
+ message-subscribed-addresses)
+ file-regexps
+ (mapcar 'funcall
+ message-subscribed-address-functions))))
+ (save-match-data
+ (when (eval (apply 'append '(or)
+ (mapcar
+ (function (lambda (regexp)
+ (mapcar
+ (function (lambda (recipient)
+ `(string-match ,regexp
+ ,recipient)))
+ recipients)))
+ mft-regexps)))
+ msg-recipients))))
+
(defun message-generate-headers (headers)
"Prepare article HEADERS.
Headers already prepared in the buffer are not modified."
(nthcdr (+ (- cut 2) surplus 1) list)))
(defun message-shorten-references (header references)
- "Trim REFERENCES to be less than 31 Message-ID long, and fold them.
+ "Trim REFERENCES to be 21 Message-ID long or less, and fold them.
If folding is disallowed, also check that the REFERENCES are less
than 988 characters long, and if they are not, trim them until they are."
- (let ((maxcount 31)
+ (let ((maxcount 21)
(count 0)
- (cut 6)
+ (cut 2)
refs)
(with-temp-buffer
(insert references)
(forward-line 2)))
(sit-for 0)))
+(defun message-beginning-of-line (&optional n)
+ "Move point to beginning of header value or to beginning of line."
+ (interactive "p")
+ (if (message-point-in-header-p)
+ (let* ((here (point))
+ (bol (progn (beginning-of-line n) (point)))
+ (eol (gnus-point-at-eol))
+ (eoh (re-search-forward ": *" eol t)))
+ (if (or (not eoh) (equal here eoh))
+ (goto-char bol)
+ (goto-char eoh)))
+ (beginning-of-line n)))
+
(defun message-buffer-name (type &optional to group)
"Return a new (unique) buffer name based on TYPE and TO."
(cond
;; list of buffers.
(setq message-buffer-list (delq (current-buffer) message-buffer-list))
(while (and message-max-buffers
- message-buffer-list
+ message-buffer-list
(>= (length message-buffer-list) message-max-buffers))
;; Kill the oldest buffer -- unless it has been changed.
(let ((buffer (pop message-buffer-list)))
;; Rename the buffer.
(if message-send-rename-function
(funcall message-send-rename-function)
- (when (string-match "\\`\\*\\(sent \\|unsent \\)?\\(.+\\)\\*[^\\*]*"
- (buffer-name))
+ ;; Note: mail-abbrevs of XEmacs renames buffer name behind Gnus.
+ (when (string-match
+ "\\`\\*\\(sent \\|unsent \\)?\\(.+\\)\\*[^\\*]*\\|\\`mail to "
+ (buffer-name))
(let ((name (match-string 2 (buffer-name)))
to group)
- (if (not (or (string-equal name "mail")
+ (if (not (or (null name)
+ (string-equal name "mail")
(string-equal name "news")))
(setq name (concat "*sent " name "*"))
+ (message-narrow-to-headers)
(setq to (message-fetch-field "to"))
(setq group (message-fetch-field "newsgroups"))
+ (widen)
(setq name
- (cond
+ (cond
(to (concat "*sent mail to "
(or (car (mail-extract-address-components to))
to) "*"))
headers)
nil switch-function yank-action actions)))))
-;;;(defvar mc-modes-alist)
(defun message-setup-1 (headers &optional replybuffer actions)
-;;; (when (and (boundp 'mc-modes-alist)
-;;; (not (assq 'message-mode mc-modes-alist)))
-;;; (push '(message-mode (encrypt . mc-encrypt-message)
-;;; (sign . mc-sign-message))
-;;; mc-modes-alist))
- (when actions
- (setq message-send-actions actions))
+ (dolist (action actions)
+ (condition-case nil
+ (add-to-list 'message-send-actions
+ `(apply ',(car action) ',(cdr action)))))
(setq message-reply-buffer replybuffer)
(goto-char (point-min))
;; Insert all the headers.
(setq message-draft-article
(nndraft-request-associate-buffer "drafts"))
(setq buffer-file-name (expand-file-name
- (if (eq system-type 'windows-nt)
+ (if (memq system-type
+ '(ms-dos ms-windows windows-nt
+ cygwin32 win32 w32
+ mswindows))
"message"
"*message*")
message-auto-save-directory))
(nconc
`((To . ,(or to "")) (Subject . ,(or subject "")))
(when other-headers other-headers))
- replybuffer)
+ replybuffer send-actions)
;; FIXME: Should return nil if failure.
t))
(Subject . ,(or subject ""))))))
(defun message-get-reply-headers (wide &optional to-address)
- (let (follow-to mct never-mct from to cc reply-to mrt mft ccalist)
+ (let (follow-to mct never-mct to cc author mft recipients)
;; Find all relevant headers we need.
- (setq from (message-fetch-field "from")
- to (message-fetch-field "to")
+ (setq to (message-fetch-field "to")
cc (message-fetch-field "cc")
mct (message-fetch-field "mail-copies-to")
- reply-to (message-fetch-field "reply-to")
- mrt (message-fetch-field "mail-reply-to")
- mft (and message-use-followup-to
- (message-fetch-field "mail-followup-to")))
+ author (or (message-fetch-field "mail-reply-to")
+ (message-fetch-field "reply-to")
+ (message-fetch-field "from")
+ "")
+ mft (and message-use-mail-followup-to
+ (message-fetch-field "mail-followup-to")))
;; Handle special values of Mail-Copies-To.
(when mct
(setq mct nil))
((or (equal (downcase mct) "always")
(equal (downcase mct) "poster"))
- (setq mct (or mrt reply-to from)))))
+ (setq mct author))))
- (if (and (not mft)
- (or (not wide)
- to-address))
- (progn
- (setq follow-to (list (cons 'To (or to-address mrt reply-to from))))
- (when (and (and wide mct)
- (not (member (cons 'To mct) follow-to)))
- (push (cons 'Cc mct) follow-to)))
- (let (ccalist)
- (save-excursion
- (message-set-work-buffer)
- (if (and mft
- message-use-followup-to
- (or (not (eq message-use-followup-to 'ask))
- (message-y-or-n-p
- (concat "Obey Mail-Followup-To? ") t "\
+ (save-match-data
+ ;; Build (textual) list of new recipient addresses.
+ (cond
+ ((not wide)
+ (setq recipients (concat ", " author)))
+ ((and mft
+ (string-match "[^ \t,]" mft)
+ (or (not (eq message-use-mail-followup-to 'ask))
+ (message-y-or-n-p "Obey Mail-Followup-To? " t "\
You should normally obey the Mail-Followup-To: header. In this
article, it has the value of
" mft "
which directs your response to " (if (string-match "," mft)
- "the specified addresses"
- "that address only") ".
+ "the specified addresses"
+ "that address only") ".
-If a message is posted to several mailing lists, Mail-Followup-To is
-often used to direct the following discussion to one list only,
+Most commonly, Mail-Followup-To is used by a mailing list poster to
+express that responses should be sent to just the list, and not the
+poster as well.
+
+If a message is posted to several mailing lists, Mail-Followup-To may
+also be used to direct the following discussion to one list only,
because discussions that are spread over several lists tend to be
fragmented and very difficult to follow.
-Also, some source/announcement lists are not indented for discussion;
+Also, some source/announcement lists are not intended for discussion;
responses here are directed to other addresses.")))
- (insert mft)
- (unless never-mct
- (insert (or mrt reply-to from "")))
- (insert (if to (concat (if (bolp) "" ", ") to "") ""))
- (insert (if mct (concat (if (bolp) "" ", ") mct) ""))
- (insert (if cc (concat (if (bolp) "" ", ") cc) "")))
- (goto-char (point-min))
- (while (re-search-forward "[ \t]+" nil t)
- (replace-match " " t t))
- ;; Remove addresses that match `rmail-dont-reply-to-names'.
- (let ((rmail-dont-reply-to-names message-dont-reply-to-names))
- (insert (prog1 (rmail-dont-reply-to (buffer-string))
- (erase-buffer))))
- (goto-char (point-min))
- ;; Perhaps "Mail-Copies-To: never" removed the only address?
- (when (eobp)
- (insert (or mrt reply-to from "")))
- (setq ccalist
- (mapcar
- (lambda (addr)
- (cons (mail-strip-quoted-names addr) addr))
- (message-tokenize-header (buffer-string))))
- (let ((s ccalist))
- (while s
- (setq ccalist (delq (assoc (car (pop s)) s) ccalist)))))
- (setq follow-to (list (cons 'To (cdr (pop ccalist)))))
- (when ccalist
- (let ((ccs (cons 'Cc (mapconcat
- (lambda (addr) (cdr addr)) ccalist ", "))))
- (when (string-match "^ +" (cdr ccs))
- (setcdr ccs (substring (cdr ccs) (match-end 0))))
- (push ccs follow-to)))))
+ (setq recipients (concat ", " mft)))
+ (to-address
+ (setq recipients (concat ", " to-address))
+ ;; If the author explicitly asked for a copy, we don't deny it to them.
+ (if mct (setq recipients (concat recipients ", " mct))))
+ (t
+ (setq recipients (if never-mct "" (concat ", " author)))
+ (if to (setq recipients (concat recipients ", " to)))
+ (if cc (setq recipients (concat recipients ", " cc)))
+ (if mct (setq recipients (concat recipients ", " mct)))))
+ (if (>= (length recipients) 2)
+ ;; Strip the leading ", ".
+ (setq recipients (substring recipients 2)))
+ ;; Squeeze whitespace.
+ (while (string-match "[ \t][ \t]+" recipients)
+ (setq recipients (replace-match " " t t recipients)))
+ ;; Remove addresses that match `rmail-dont-reply-to-names'.
+ (let ((rmail-dont-reply-to-names message-dont-reply-to-names))
+ (setq recipients (rmail-dont-reply-to recipients)))
+ ;; Perhaps "Mail-Copies-To: never" removed the only address?
+ (if (string-equal recipients "")
+ (setq recipients author))
+ ;; Convert string to a list of (("foo@bar" . "Name <foo@bar>") ...).
+ (setq recipients
+ (mapcar
+ (lambda (addr)
+ (cons (mail-strip-quoted-names addr) addr))
+ (message-tokenize-header recipients)))
+ ;; Remove first duplicates. (Why not all duplicates? Is this a bug?)
+ (let ((s recipients))
+ (while s
+ (setq recipients (delq (assoc (car (pop s)) s) recipients))))
+ ;; Build the header alist. Allow the user to be asked whether
+ ;; or not to reply to all recipients in a wide reply.
+ (setq follow-to (list (cons 'To (cdr (pop recipients)))))
+ (when (and recipients
+ (or (not message-wide-reply-confirm-recipients)
+ (y-or-n-p "Reply to all recipients? ")))
+ (setq recipients (mapconcat
+ (lambda (addr) (cdr addr)) recipients ", "))
+ (if (string-match "^ +" recipients)
+ (setq recipients (substring recipients (match-end 0))))
+ (push (cons 'Cc recipients) follow-to)))
follow-to))
-
;;;###autoload
(defun message-reply (&optional to-address wide)
"Start editing a reply to the article in the current buffer."
date (message-fetch-field "date")
from (message-fetch-field "from")
subject (or (message-fetch-field "subject") "none"))
- (when gnus-list-identifiers
- (setq subject (message-strip-list-identifiers subject)))
- (setq subject (concat "Re: " (message-strip-subject-re subject)))
+ (when gnus-list-identifiers
+ (setq subject (message-strip-list-identifiers subject)))
+ (setq subject (concat "Re: " (message-strip-subject-re subject)))
- (when (and (setq gnus-warning (message-fetch-field "gnus-warning"))
- (string-match "<[^>]+>" gnus-warning))
- (setq message-id (match-string 0 gnus-warning)))
+ (when (and (setq gnus-warning (message-fetch-field "gnus-warning"))
+ (string-match "<[^>]+>" gnus-warning))
+ (setq message-id (match-string 0 gnus-warning)))
- (unless follow-to
- (setq follow-to (message-get-reply-headers wide to-address))))
+ (unless follow-to
+ (setq follow-to (message-get-reply-headers wide to-address))))
(unless (message-mail-user-agent)
(message-pop-to-buffer
because discussions that are spread over several newsgroup tend to
be fragmented and very difficult to follow.
-Also, some source/announcement newsgroups are not indented for discussion;
+Also, some source/announcement newsgroups are not intended for discussion;
responses here are directed to other newsgroups."))
(cons 'Newsgroups followup-to)
(cons 'Newsgroups newsgroups))))))
message-id (message-fetch-field "message-id" t)
distribution (message-fetch-field "distribution")))
;; Make sure that this article was written by the user.
- (unless (or (message-gnksa-enable-p 'cancel-messages)
- (and sender
- (string-equal
- (downcase sender)
- (downcase (message-make-sender))))
- (string-equal
- (downcase (cadr (mail-extract-address-components from)))
- (downcase (cadr (mail-extract-address-components
- (message-make-from))))))
+ (unless (or
+ ;; Canlock-logic as suggested by Per Abrahamsen
+ ;; <abraham@dina.kvl.dk>
+ ;;
+ ;; IF article has cancel-lock THEN
+ ;; IF we can verify it THEN
+ ;; issue cancel
+ ;; ELSE
+ ;; error: cancellock: article is not yours
+ ;; ELSE
+ ;; Use old rules, comparing sender...
+ (if (message-fetch-field "Cancel-Lock")
+ (if (null (canlock-verify))
+ t
+ (error "Failed to verify Cancel-lock: This article is not yours"))
+ nil)
+ (message-gnksa-enable-p 'cancel-messages)
+ (and sender
+ (string-equal
+ (downcase sender)
+ (downcase (message-make-sender))))
+ (string-equal
+ (downcase (cadr (mail-extract-address-components from)))
+ (downcase (cadr (mail-extract-address-components
+ (message-make-from))))))
(error "This article is not yours"))
(when (yes-or-no-p "Do you really want to cancel this article? ")
;; Make control message.
(sender (message-fetch-field "sender"))
(from (message-fetch-field "from")))
;; Check whether the user owns the article that is to be superseded.
- (unless (or (message-gnksa-enable-p 'cancel-messages)
+ (unless (or
+ ;; Canlock-logic as suggested by Per Abrahamsen
+ ;; <abraham@dina.kvl.dk>
+ ;;
+ ;; IF article has cancel-lock THEN
+ ;; IF we can verify it THEN
+ ;; issue cancel
+ ;; ELSE
+ ;; error: cancellock: article is not yours
+ ;; ELSE
+ ;; Use old rules, comparing sender...
+ (if (message-fetch-field "Cancel-Lock")
+ (if (null (canlock-verify))
+ t
+ (error "Failed to verify Cancel-lock: This article is not yours"))
+ nil)
+ (message-gnksa-enable-p 'cancel-messages)
(and sender
(string-equal
(downcase sender)
"Remove junk like \"Re:\", \"(fwd)\", etc. added to subject string SUBJECT.
Previous forwarders, replyers, etc. may add it."
(with-temp-buffer
- (insert-string subject)
+ (insert subject)
(goto-char (point-min))
;; strip Re/Fwd stuff off the beginning
(while (re-search-forward
Source is the sender, and if the original message was news, Source is
the list of newsgroups is was posted to."
(concat "["
- (let ((prefix
- (or (message-fetch-field
- (if (message-news-p) "newsgroups" "from"))
- "(nowhere)")))
- (if message-forward-decoded-p
- prefix
- (mail-decode-encoded-word-string prefix)))
+ (let ((prefix
+ (or (message-fetch-field "newsgroups")
+ (message-fetch-field "from")
+ "(nowhere)")))
+ (if message-forward-decoded-p
+ prefix
+ (mail-decode-encoded-word-string prefix)))
"] " subject))
(defun message-forward-subject-fwd (subject)
(eval-when-compile
(defvar gnus-article-decoded-p))
+
;;;###autoload
(defun message-forward (&optional news digest)
"Forward the current message via mail.
Optional DIGEST will use digest to forward."
(interactive "P")
(let* ((cur (current-buffer))
- (message-forward-decoded-p
+ (message-forward-decoded-p
(if (local-variable-p 'gnus-article-decoded-p (current-buffer))
- gnus-article-decoded-p ;; In an article buffer.
+ gnus-article-decoded-p ;; In an article buffer.
message-forward-decoded-p))
- (subject (message-make-forward-subject))
- art-beg)
+ (subject (message-make-forward-subject)))
(if news
(message-news nil subject)
(message-mail nil subject))
- ;; Put point where we want it before inserting the forwarded
- ;; message.
- (if message-forward-before-signature
- (message-goto-body)
- (goto-char (point-max)))
- (if message-forward-as-mime
- (if digest
- (insert "\n<#multipart type=digest>\n")
- (if message-forward-show-mml
- (insert "\n\n<#mml type=message/rfc822 disposition=inline>\n")
- (insert "\n\n<#part type=message/rfc822 disposition=inline raw=t>\n")))
- (insert "\n-------------------- Start of forwarded message --------------------\n"))
- (let ((b (point)) e)
+ (message-forward-make-body cur digest)))
+
+;;;###autoload
+(defun message-forward-make-body (forward-buffer &optional digest)
+ ;; Put point where we want it before inserting the forwarded
+ ;; message.
+ (if message-forward-before-signature
+ (message-goto-body)
+ (goto-char (point-max)))
+ (if message-forward-as-mime
(if digest
- (if message-forward-as-mime
- (insert-buffer-substring cur)
- (mml-insert-buffer cur))
- (if (and message-forward-show-mml
- (not message-forward-decoded-p))
- (insert
- (with-temp-buffer
- (mm-disable-multibyte-mule4) ;; Must copy buffer in unibyte mode
+ (insert "\n<#multipart type=digest>\n")
+ (if message-forward-show-mml
+ (insert "\n\n<#mml type=message/rfc822 disposition=inline>\n")
+ (insert "\n\n<#part type=message/rfc822 disposition=inline raw=t>\n")))
+ (insert "\n-------------------- Start of forwarded message --------------------\n"))
+ (let ((b (point)) e)
+ (if digest
+ (if message-forward-as-mime
+ (insert-buffer-substring forward-buffer)
+ (mml-insert-buffer forward-buffer))
+ (if (and message-forward-show-mml
+ (not message-forward-decoded-p))
+ (insert
+ (with-temp-buffer
+ (mm-disable-multibyte-mule4) ;; Must copy buffer in unibyte mode
(insert
- (with-current-buffer cur
+ (with-current-buffer forward-buffer
(mm-string-as-unibyte (buffer-string))))
(mm-enable-multibyte-mule4)
(mime-to-mml)
(when (looking-at "From ")
(replace-match "X-From-Line: "))
(buffer-string)))
- (save-restriction
- (narrow-to-region (point) (point))
- (mml-insert-buffer cur)
- (goto-char (point-min))
- (when (looking-at "From ")
- (replace-match "X-From-Line: "))
- (goto-char (point-max)))))
- (setq e (point))
- (if message-forward-as-mime
- (if digest
- (insert "<#/multipart>\n")
- (if message-forward-show-mml
- (insert "<#/mml>\n")
- (insert "<#/part>\n")))
- (insert "\n-------------------- End of forwarded message --------------------\n"))
- (if (and digest message-forward-as-mime)
- (save-restriction
- (narrow-to-region b e)
- (goto-char b)
- (narrow-to-region (point)
- (or (search-forward "\n\n" nil t) (point)))
- (delete-region (point-min) (point-max)))
- (when (and (not current-prefix-arg)
- message-forward-ignored-headers)
- (save-restriction
- (narrow-to-region b e)
- (goto-char b)
- (narrow-to-region (point)
- (or (search-forward "\n\n" nil t) (point)))
- (message-remove-header message-forward-ignored-headers t)))))
- (message-position-point)))
+ (save-restriction
+ (narrow-to-region (point) (point))
+ (mml-insert-buffer forward-buffer)
+ (goto-char (point-min))
+ (when (looking-at "From ")
+ (replace-match "X-From-Line: "))
+ (goto-char (point-max)))))
+ (setq e (point))
+ (if message-forward-as-mime
+ (if digest
+ (insert "<#/multipart>\n")
+ (if message-forward-show-mml
+ (insert "<#/mml>\n")
+ (insert "<#/part>\n")))
+ (insert "\n-------------------- End of forwarded message --------------------\n"))
+ (if (and digest message-forward-as-mime)
+ (save-restriction
+ (narrow-to-region b e)
+ (goto-char b)
+ (narrow-to-region (point)
+ (or (search-forward "\n\n" nil t) (point)))
+ (delete-region (point-min) (point-max)))
+ (when (and (not current-prefix-arg)
+ message-forward-ignored-headers)
+ (save-restriction
+ (narrow-to-region b e)
+ (goto-char b)
+ (narrow-to-region (point)
+ (or (search-forward "\n\n" nil t) (point)))
+ (message-remove-header message-forward-ignored-headers t)))))
+ (message-position-point))
+
+;;;###autoload
+(defun message-forward-rmail-make-body (forward-buffer)
+ (save-window-excursion
+ (set-buffer forward-buffer)
+ (let (rmail-enable-mime)
+ (rmail-toggle-header 0)))
+ (message-forward-make-body forward-buffer))
+
+;;;###autoload
+(defun message-insinuate-rmail ()
+ "Let RMAIL uses message to forward."
+ (interactive)
+ (setq rmail-enable-mime-composing t)
+ (setq rmail-insert-mime-forwarded-message-function
+ 'message-forward-rmail-make-body))
;;;###autoload
(defun message-resend (address)
(undo-boundary)
(goto-char (point-min))
(search-forward "\n\n" nil t)
- (or (and (re-search-forward message-unsent-separator nil t)
- (forward-line 1))
- (re-search-forward "^Return-Path:.*\n" nil t))
- ;; We remove everything before the bounced mail.
- (delete-region
- (point-min)
- (if (re-search-forward "^[^ \n\t]+:" nil t)
- (match-beginning 0)
- (point))))
+ (if (or (and (re-search-forward message-unsent-separator nil t)
+ (forward-line 1))
+ (re-search-forward "^Return-Path:.*\n" nil t))
+ ;; We remove everything before the bounced mail.
+ (delete-region
+ (point-min)
+ (if (re-search-forward "^[^ \n\t]+:" nil t)
+ (match-beginning 0)
+ (point)))
+ (when (re-search-backward "^.?From .*\n" nil t)
+ (delete-region (match-beginning 0) (match-end 0)))))
(mm-enable-multibyte)
(mime-to-mml)
(save-restriction
(tool-bar-add-item-from-menu
'message-dont-send "cancel" message-mode-map)
(tool-bar-add-item-from-menu
- 'mml-attach-file "attach" message-mode-map)
+ 'mml-attach-file "attach" mml-mode-map)
(tool-bar-add-item-from-menu
'ispell-message "spell" message-mode-map)
+ (tool-bar-add-item-from-menu
+ 'message-insert-importance-high "important"
+ message-mode-map)
+ (tool-bar-add-item-from-menu
+ 'message-insert-importance-low "unimportant"
+ message-mode-map)
tool-bar-map)))))
;;; Group name completion.
-(defvar message-newgroups-header-regexp
+(defcustom message-newgroups-header-regexp
"^\\(Newsgroups\\|Followup-To\\|Posted-To\\|Gcc\\):"
- "Regexp that match headers that lists groups.")
+ "Regexp that match headers that lists groups."
+ :group 'message
+ :type 'regexp)
+
+(defcustom message-completion-alist
+ (list (cons message-newgroups-header-regexp 'message-expand-group)
+ '("^\\(Resent-\\)?\\(To\\|B?Cc\\):" . message-expand-name))
+ "Alist of (RE . FUN). Use FUN for completion on header lines matching RE."
+ :group 'message
+ :type '(alist :key-type regexp :value-type function))
+
+(defcustom message-tab-body-function nil
+ "*Function to execute when `message-tab' (TAB) is executed in the body.
+If nil, the function bound in `text-mode-map' or `global-map' is executed."
+ :group 'message
+ :type 'function)
(defun message-tab ()
- "Expand group names in Newsgroups and Followup-To headers.
-Do a `tab-to-tab-stop' if not in those headers."
+ "Complete names according to `message-completion-alist'.
+Execute function specified by `message-tab-body-function' when not in
+those headers."
(interactive)
- (if (let ((mail-abbrev-mode-regexp message-newgroups-header-regexp))
- (mail-abbrev-in-expansion-header-p))
- (message-expand-group)
- (tab-to-tab-stop)))
+ (let ((alist message-completion-alist))
+ (while (and alist
+ (let ((mail-abbrev-mode-regexp (caar alist)))
+ (not (mail-abbrev-in-expansion-header-p))))
+ (setq alist (cdr alist)))
+ (funcall (or (cdar alist) message-tab-body-function
+ (lookup-key text-mode-map "\t")
+ (lookup-key global-map "\t")
+ 'indent-relative))))
(defun message-expand-group ()
"Expand the group name under point."
(goto-char (point-min))
(delete-region (point) (progn (forward-line 3) (point))))))))))
+(defun message-expand-name ()
+ (if (fboundp 'bbdb-complete-name)
+ (bbdb-complete-name)
+ (expand-abbrev)))
+
;;; Help stuff.
(defun message-talkative-question (ask question show &rest text)
;; /usr/bin/mail.
(unless content-type-p
(goto-char (point-min))
- (re-search-forward "^MIME-Version:")
- (forward-line 1)
- (insert "Content-Type: text/plain; charset=us-ascii\n")))))
+ ;; For unknown reason, MIME-Version doesn't exist.
+ (when (re-search-forward "^MIME-Version:" nil t)
+ (forward-line 1)
+ (insert "Content-Type: text/plain; charset=us-ascii\n"))))))
(defun message-read-from-minibuffer (prompt)
"Read from the minibuffer while providing abbrev expansion."
(message-fetch-field "from")))
(message-options-set 'message-recipients
(mail-strip-quoted-names
- (concat
- (or (message-fetch-field "to") "") ", "
- (or (message-fetch-field "cc") "") ", "
- (or (message-fetch-field "bcc") ""))))))
+ (let ((to (message-fetch-field "to"))
+ (cc (message-fetch-field "cc"))
+ (bcc (message-fetch-field "bcc")))
+ (concat
+ (or to "")
+ (if (and to cc) ", ")
+ (or cc "")
+ (if (and (or to cc) bcc) ", ")
+ (or bcc "")))))))
(when (featurep 'xemacs)
(require 'messagexmas)
(defun message-xmas-redefine ()
"Redefine message functions for XEmacs."
- (defalias 'message-exchange-point-and-mark
+ (defalias 'message-exchange-point-and-mark
'message-xmas-exchange-point-and-mark)
(when (>= emacs-major-version 20)
;;; mm-bodies.el --- Functions for decoding MIME things
-;; Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+
+;; Copyright (C) 1998, 1999, 2000, 2001
+;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;; MORIOKA Tomohiko <morioka@jaist.ac.jp>
(if (re-search-forward "[^\x0-\x7f]" nil t)
(or mail-parse-charset
(message-options-get 'mm-encody-body-charset)
- (message-options-set
+ (message-options-set
'mm-encody-body-charset
(mm-read-charset "Charset used in the article: ")))
;; The logic in `mml-generate-mime-1' confirms that it's OK
(mm-encode-coding-region (point-min) (point-max) charset)
charset)
(goto-char (point-min))
- (let ((charsets (mm-find-mime-charset-region (point-min) (point-max)))
+ (let ((charsets (mm-find-mime-charset-region (point-min) (point-max)
+ mm-hack-charsets))
start)
(cond
;; No encoding.
(defun mm-body-encoding (charset &optional encoding)
"Do Content-Transfer-Encoding and return the encoding of the current buffer."
+ (when (stringp encoding)
+ (setq encoding (intern (downcase encoding))))
(let ((bits (mm-body-7-or-8))
(longp (mm-long-lines-p 1000)))
(require 'message)
;;;
(defun mm-decode-content-transfer-encoding (encoding &optional type)
+ "Decodes buffer encoded with ENCODING, returning success status.
+If TYPE is `text/plain' CRLF->LF translation may occur."
(prog1
(condition-case error
(cond
((eq encoding 'quoted-printable)
- (quoted-printable-decode-region (point-min) (point-max)))
+ (quoted-printable-decode-region (point-min) (point-max))
+ t)
((eq encoding 'base64)
(base64-decode-region
(point-min)
(point))))
((memq encoding '(7bit 8bit binary))
;; Do nothing.
- )
+ t)
((null encoding)
;; Do nothing.
- )
+ t)
((memq encoding '(x-uuencode x-uue))
(require 'mm-uu)
- (funcall mm-uu-decode-function (point-min) (point-max)))
+ (funcall mm-uu-decode-function (point-min) (point-max))
+ t)
((eq encoding 'x-binhex)
(require 'mm-uu)
- (funcall mm-uu-binhex-decode-function (point-min) (point-max)))
+ (funcall mm-uu-binhex-decode-function (point-min) (point-max))
+ t)
((functionp encoding)
- (funcall encoding (point-min) (point-max)))
+ (funcall encoding (point-min) (point-max))
+ t)
(t
(message "Unknown encoding %s; defaulting to 8bit" encoding)))
(error
The characters in CHARSET should then be decoded."
(if (stringp charset)
(setq charset (intern (downcase charset))))
- (if (or (not charset)
+ (if (or (not charset)
(eq 'gnus-all mail-parse-ignored-charsets)
(memq 'gnus-all mail-parse-ignored-charsets)
(memq charset mail-parse-ignored-charsets))
(if (and (not coding-system)
(listp mail-parse-ignored-charsets)
(memq 'gnus-unknown mail-parse-ignored-charsets))
- (setq coding-system
+ (setq coding-system
(mm-charset-to-coding-system mail-parse-charset)))
(when (and charset coding-system
;; buffer-file-coding-system
"Decode STRING with CHARSET."
(when (stringp charset)
(setq charset (intern (downcase charset))))
- (when (or (not charset)
+ (when (or (not charset)
(eq 'gnus-all mail-parse-ignored-charsets)
(memq 'gnus-all mail-parse-ignored-charsets)
(memq charset mail-parse-ignored-charsets))
(if (and (not coding-system)
(listp mail-parse-ignored-charsets)
(memq 'gnus-unknown mail-parse-ignored-charsets))
- (setq coding-system
+ (setq coding-system
(mm-charset-to-coding-system mail-parse-charset)))
(when (and charset coding-system
(mm-multibyte-p)
(provide 'mm-bodies)
-;; mm-bodies.el ends here
+;;; mm-bodies.el ends here
;;; Commentary:
+;; Jaap-Henk Hoepman (jhh@xs4all.nl):
+;;
+;; Added support for delayed destroy of external MIME viewers. All external
+;; viewers for mime types in mm-keep-viewer-alive-types will remain active
+;; after switching articles or groups, and will only be removed when exiting
+;; gnus.
+;;
+
;;; Code:
(require 'mail-parse)
(require 'mailcap)
(require 'mm-bodies)
-(eval-when-compile (require 'cl))
+(eval-when-compile (require 'cl)
+ (require 'term))
(eval-and-compile
(autoload 'mm-inline-partial "mm-partial")
(autoload 'mm-inline-external-body "mm-extern")
(autoload 'mm-insert-inline "mm-view"))
+(add-hook 'gnus-exit-gnus-hook 'mm-destroy-postponed-undisplay-list)
+
(defgroup mime-display ()
"Display of MIME in mail and news articles."
:link '(custom-manual "(emacs-mime)Customization")
(lambda (handle)
(locate-library "diff-mode")))
("application/emacs-lisp" mm-display-elisp-inline identity)
+ ("application/x-emacs-lisp" mm-display-elisp-inline identity)
("text/html"
mm-inline-text
(lambda (handle)
("application/pgp-signature" ignore identity)
("application/x-pkcs7-signature" ignore identity)
("application/pkcs7-signature" ignore identity)
+ ("application/x-pkcs7-mime" ignore identity)
+ ("application/pkcs7-mime" ignore identity)
("multipart/alternative" ignore identity)
("multipart/mixed" ignore identity)
- ("multipart/related" ignore identity))
+ ("multipart/related" ignore identity)
+ ;; Disable audio and image
+ ("audio/.*" ignore ignore)
+ ("image/.*" ignore ignore)
+ ;; Default to displaying as text
+ (".*" mm-inline-text mm-readable-p))
"Alist of media types/tests saying whether types can be displayed inline."
:type '(repeat (list (string :tag "MIME type")
(function :tag "Display function")
'("image/.*" "text/.*" "message/delivery-status" "message/rfc822"
"message/partial" "message/external-body" "application/emacs-lisp"
"application/pgp-signature" "application/x-pkcs7-signature"
- "application/pkcs7-signature")
- "List of media types that are to be displayed inline."
+ "application/pkcs7-signature" "application/x-pkcs7-mime"
+ "application/pkcs7-mime")
+ "List of media types that are to be displayed inline.
+See also `mm-inline-media-tests', which says how to display a media
+type inline."
+ :type '(repeat string)
+ :group 'mime-display)
+
+(defcustom mm-keep-viewer-alive-types
+ '("application/postscript" "application/msword" "application/vnd.ms-excel"
+ "application/pdf" "application/x-dvi")
+ "List of media types for which the external viewer will not be killed
+when selecting a different article."
:type '(repeat string)
:group 'mime-display)
-
+
(defcustom mm-automatic-display
'("text/plain" "text/enriched" "text/richtext" "text/html"
"text/x-vcard" "image/.*" "message/delivery-status" "multipart/.*"
"message/rfc822" "text/x-patch" "application/pgp-signature"
"application/emacs-lisp" "application/x-pkcs7-signature"
- "application/pkcs7-signature")
+ "application/pkcs7-signature" "application/x-pkcs7-mime"
+ "application/pkcs7-mime")
"A list of MIME types to be displayed automatically."
:type '(repeat string)
:group 'mime-display)
-(defcustom mm-attachment-override-types '("text/x-vcard")
+(defcustom mm-attachment-override-types '("text/x-vcard"
+ "application/pkcs7-mime"
+ "application/x-pkcs7-mime"
+ "application/pkcs7-signature"
+ "application/x-pkcs7-signature")
"Types to have \"attachment\" ignored if they can be displayed inline."
:type '(repeat string)
:group 'mime-display)
:type 'boolean
:group 'mime-display)
+(defvar mm-file-name-rewrite-functions nil
+ "*List of functions used for rewriting file names of MIME parts.
+Each function takes a file name as input and returns a file name.
+
+Ready-made functions include
+`mm-file-name-delete-whitespace',
+`mm-file-name-trim-whitespace',
+`mm-file-name-collapse-whitespace',
+`mm-file-name-replace-whitespace',
+`capitalize', `downcase', `upcase', and
+`upcase-initials'.")
+
+(defvar mm-path-name-rewrite-functions nil
+ "*List of functions used for rewriting path names of MIME parts.
+This is used when viewing parts externally , and is meant for
+transforming the path name so that non-compliant programs can
+find the file where it's saved.
+
+Each function takes a file name as input and returns a file name.")
+
+(defvar mm-file-name-replace-whitespace nil
+ "String used for replacing whitespace characters; default is `\"_\"'.")
+
(defcustom mm-default-directory nil
"The default directory where mm will save files.
If not set, `default-directory' will be used."
- :type 'directory
+ :type '(choice directory (const :tag "Default" nil))
+ :group 'mime-display)
+
+(defcustom mm-external-terminal-program "xterm"
+ "The program to start an external terminal."
+ :type 'string
:group 'mime-display)
;;; Internal variables.
(defvar mm-dissection-list nil)
(defvar mm-last-shell-command "")
(defvar mm-content-id-alist nil)
+(defvar mm-postponed-undisplay-list nil)
;; According to RFC2046, in particular, in a digest, the default
;; Content-Type value for a body part is changed from "text/plain" to
(setq alist (cdr alist)))
(nreverse plist)))
+(defun mm-keep-viewer-alive-p (handle)
+ "Say whether external viewer for HANDLE should stay alive."
+ (let ((types mm-keep-viewer-alive-types)
+ (type (mm-handle-media-type handle))
+ ty)
+ (catch 'found
+ (while (setq ty (pop types))
+ (when (string-match ty type)
+ (throw 'found t))))))
+
+(defun mm-handle-set-external-undisplayer (handle function)
+ "Set the undisplayer for this handle; postpone undisplaying of viewers
+for types in mm-keep-viewer-alive-types."
+ (if (mm-keep-viewer-alive-p handle)
+ (let ((new-handle (copy-sequence handle)))
+ (mm-handle-set-undisplayer new-handle function)
+ (mm-handle-set-undisplayer handle nil)
+ (push new-handle mm-postponed-undisplay-list))
+ (mm-handle-set-undisplayer handle function)))
+
+(defun mm-destroy-postponed-undisplay-list ()
+ (when mm-postponed-undisplay-list
+ (message "Destroying external MIME viewers")
+ (mm-destroy-parts mm-postponed-undisplay-list)))
+
(defun mm-dissect-buffer (&optional no-strict-mime)
"Dissect the current buffer and return a list of MIME handles."
(save-excursion
(let ((mm-dissect-default-type (if (equal subtype "digest")
"message/rfc822"
"text/plain")))
- (add-text-properties 0 (length (car ctl))
- (mm-alist-to-plist (cdr ctl)) (car ctl))
+ (add-text-properties 0 (length (car ctl))
+ (mm-alist-to-plist (cdr ctl)) (car ctl))
;; what really needs to be done here is a way to link a
;; MIME handle back to it's parent MIME handle (in a multilevel
;; MIME article). That would probably require changing
;; the mm-handle API so we simply store the multipart buffert
;; name as a text property of the "multipart/whatever" string.
- (add-text-properties 0 (length (car ctl))
+ (add-text-properties 0 (length (car ctl))
(list 'buffer (mm-copy-to-buffer))
- (car ctl))
- (add-text-properties 0 (length (car ctl))
+ (car ctl))
+ (add-text-properties 0 (length (car ctl))
(list 'from from)
- (car ctl))
+ (car ctl))
(cons (car ctl) (mm-dissect-multipart ctl))))
(t
- (mm-dissect-singlepart
- ctl
- (and cte (intern (downcase (mail-header-remove-whitespace
- (mail-header-remove-comments
- cte)))))
- no-strict-mime
- (and cd (ignore-errors (mail-header-parse-content-disposition cd)))
- description id))))
+ (mm-possibly-verify-or-decrypt
+ (mm-dissect-singlepart
+ ctl
+ (and cte (intern (downcase (mail-header-remove-whitespace
+ (mail-header-remove-comments
+ cte)))))
+ no-strict-mime
+ (and cd (ignore-errors
+ (mail-header-parse-content-disposition cd)))
+ description id)
+ ctl))))
(when id
(when (string-match " *<\\(.*\\)> *" id)
(setq id (match-string 1 id)))
(mm-remove-part handle)
(let* ((type (mm-handle-media-type handle))
(method (mailcap-mime-info type)))
- (if (mm-inlined-p handle)
+ (if (and (mm-inlinable-p handle)
+ (mm-inlined-p handle))
(progn
(forward-line 1)
(mm-display-inline handle)
(mm-handle-set-undisplayer handle mm)))))
;; The function is a string to be executed.
(mm-insert-part handle)
- (let* ((dir (make-temp-name (expand-file-name "emm." mm-tmp-directory)))
- (filename (mail-content-type-get
- (mm-handle-disposition handle) 'filename))
+ (let* ((dir (make-temp-name
+ (expand-file-name "emm." mm-tmp-directory)))
+ (filename (or
+ (mail-content-type-get
+ (mm-handle-disposition handle) 'filename)
+ (mail-content-type-get
+ (mm-handle-type handle) 'name)))
(mime-info (mailcap-mime-info
(mm-handle-media-type handle) t))
(needsterm (or (assoc "needsterm" mime-info)
(let ((coding-system-for-write mm-binary-coding-system))
(write-region (point-min) (point-max) file nil 'nomesg))
(message "Viewing with %s" method)
- (cond (needsterm
- (unwind-protect
- (start-process "*display*" nil
- "xterm"
- "-e" shell-file-name
- shell-command-switch
- (mm-mailcap-command
- method file (mm-handle-type handle)))
- (mm-handle-set-undisplayer handle (cons file buffer)))
- (message "Displaying %s..." (format method file))
- 'external)
- (copiousoutput
- (with-current-buffer outbuf
- (forward-line 1)
- (mm-insert-inline
- handle
- (unwind-protect
- (progn
- (call-process shell-file-name nil
- (setq buffer
- (generate-new-buffer " *mm*"))
- nil
- shell-command-switch
- (mm-mailcap-command
- method file (mm-handle-type handle)))
- (if (buffer-live-p buffer)
- (save-excursion
- (set-buffer buffer)
- (buffer-string))))
- (progn
- (ignore-errors (delete-file file))
- (ignore-errors (delete-directory
- (file-name-directory file)))
- (ignore-errors (kill-buffer buffer))))))
- 'inline)
- (t
- (unwind-protect
- (start-process "*display*"
- (setq buffer
- (generate-new-buffer " *mm*"))
+ (cond
+ (needsterm
+ (unwind-protect
+ (if window-system
+ (start-process "*display*" nil
+ mm-external-terminal-program
+ "-e" shell-file-name
+ shell-command-switch
+ (mm-mailcap-command
+ method file (mm-handle-type handle)))
+ (require 'term)
+ (require 'gnus-win)
+ (set-buffer
+ (setq buffer
+ (make-term "display"
shell-file-name
+ nil
shell-command-switch
(mm-mailcap-command
- method file (mm-handle-type handle)))
- (mm-handle-set-undisplayer handle (cons file buffer)))
- (message "Displaying %s..." (format method file))
- 'external)))))))
+ method file
+ (mm-handle-type handle)))))
+ (term-mode)
+ (term-char-mode)
+ (set-process-sentinel
+ (get-buffer-process buffer)
+ `(lambda (process state)
+ (if (eq 'exit (process-status process))
+ (gnus-configure-windows
+ ',gnus-current-window-configuration))))
+ (gnus-configure-windows 'display-term))
+ (mm-handle-set-external-undisplayer handle (cons file buffer)))
+ (message "Displaying %s..." (format method file))
+ 'external)
+ (copiousoutput
+ (with-current-buffer outbuf
+ (forward-line 1)
+ (mm-insert-inline
+ handle
+ (unwind-protect
+ (progn
+ (call-process shell-file-name nil
+ (setq buffer
+ (generate-new-buffer " *mm*"))
+ nil
+ shell-command-switch
+ (mm-mailcap-command
+ method file (mm-handle-type handle)))
+ (if (buffer-live-p buffer)
+ (save-excursion
+ (set-buffer buffer)
+ (buffer-string))))
+ (progn
+ (ignore-errors (delete-file file))
+ (ignore-errors (delete-directory
+ (file-name-directory file)))
+ (ignore-errors (kill-buffer buffer))))))
+ 'inline)
+ (t
+ (unwind-protect
+ (start-process "*display*"
+ (setq buffer
+ (generate-new-buffer " *mm*"))
+ shell-file-name
+ shell-command-switch
+ (mm-mailcap-command
+ method file (mm-handle-type handle)))
+ (mm-handle-set-external-undisplayer
+ handle (cons file buffer)))
+ (message "Displaying %s..." (format method file))
+ 'external)))))))
(defun mm-mailcap-command (method file type-list)
(let ((ctl (cdr type-list))
(push "%" out))
((string= total "%s")
(setq uses-stdin nil)
- (push (mm-quote-arg file) out))
+ (push (mm-quote-arg
+ (gnus-map-function mm-path-name-rewrite-functions file)) out))
((string= total "%t")
(push (mm-quote-arg (car type-list)) out))
(t
(push (mm-quote-arg (or (cdr (assq (intern sub) ctl)) "")) out))))
(push (substring method beg (length method)) out)
- (if uses-stdin
- (progn
- (push "<" out)
- (push (mm-quote-arg file) out)))
+ (when uses-stdin
+ (push "<" out)
+ (push (mm-quote-arg
+ (gnus-map-function mm-path-name-rewrite-functions file))
+ out))
(mapconcat 'identity (nreverse out) "")))
(defun mm-remove-parts (handles)
((consp object)
(ignore-errors (delete-file (car object)))
(ignore-errors (delete-directory (file-name-directory (car object))))
- (ignore-errors (kill-buffer (cdr object))))
+ (ignore-errors (and (cdr object) (kill-buffer (cdr object)))))
((bufferp object)
(when (buffer-live-p object)
(kill-buffer object)))))
(when (string-match (car elem) type)
(return elem))))
+(defun mm-automatic-display-p (handle)
+ "Say whether the user wants HANDLE to be displayed automatically."
+ (let ((methods mm-automatic-display)
+ (type (mm-handle-media-type handle))
+ method result)
+ (while (setq method (pop methods))
+ (when (and (not (mm-inline-override-p handle))
+ (string-match method type))
+ (setq result t
+ methods nil)))
+ result))
+
(defun mm-inlinable-p (handle)
"Say whether HANDLE can be displayed inline."
(let ((alist mm-inline-media-tests)
(pop alist))
test))
-(defun mm-automatic-display-p (handle)
- "Say whether the user wants HANDLE to be displayed automatically."
- (let ((methods mm-automatic-display)
- (type (mm-handle-media-type handle))
- method result)
- (while (setq method (pop methods))
- (when (and (not (mm-inline-override-p handle))
- (string-match method type)
- (mm-inlinable-p handle))
- (setq result t
- methods nil)))
- result))
-
(defun mm-inlined-p (handle)
- "Say whether the user wants HANDLE to be displayed automatically."
+ "Say whether the user wants HANDLE to be displayed inline."
(let ((methods mm-inlined-types)
(type (mm-handle-media-type handle))
method result)
(while (setq method (pop methods))
(when (and (not (mm-inline-override-p handle))
- (string-match method type)
- (mm-inlinable-p handle))
+ (string-match method type))
(setq result t
methods nil)))
result))
(save-excursion
(if (member (mm-handle-media-supertype handle) '("text" "message"))
(with-temp-buffer
- (insert-buffer-substring (mm-handle-buffer handle))
- (mm-decode-content-transfer-encoding
- (mm-handle-encoding handle)
- (mm-handle-media-type handle))
- (let ((temp (current-buffer)))
- (set-buffer cur)
- (insert-buffer-substring temp)))
+ (insert-buffer-substring (mm-handle-buffer handle))
+ (prog1
+ (mm-decode-content-transfer-encoding
+ (mm-handle-encoding handle)
+ (mm-handle-media-type handle))
+ (let ((temp (current-buffer)))
+ (set-buffer cur)
+ (insert-buffer-substring temp))))
(mm-with-unibyte-buffer
(insert-buffer-substring (mm-handle-buffer handle))
- (mm-decode-content-transfer-encoding
- (mm-handle-encoding handle)
- (mm-handle-media-type handle))
- (let ((temp (current-buffer)))
- (set-buffer cur)
- (insert-buffer-substring temp)))))))
+ (prog1
+ (mm-decode-content-transfer-encoding
+ (mm-handle-encoding handle)
+ (mm-handle-media-type handle))
+ (let ((temp (current-buffer)))
+ (set-buffer cur)
+ (insert-buffer-substring temp))))))))
+
+(defun mm-file-name-delete-whitespace (file-name)
+ "Remove all whitespace characters from FILE-NAME."
+ (while (string-match "\\s-+" file-name)
+ (setq file-name (replace-match "" t t file-name)))
+ file-name)
+
+(defun mm-file-name-trim-whitespace (file-name)
+ "Remove leading and trailing whitespace characters from FILE-NAME."
+ (when (string-match "\\`\\s-+" file-name)
+ (setq file-name (substring file-name (match-end 0))))
+ (when (string-match "\\s-+\\'" file-name)
+ (setq file-name (substring file-name 0 (match-beginning 0))))
+ file-name)
+
+(defun mm-file-name-collapse-whitespace (file-name)
+ "Collapse multiple whitespace characters in FILE-NAME."
+ (while (string-match "\\s-\\s-+" file-name)
+ (setq file-name (replace-match " " t t file-name)))
+ file-name)
+
+(defun mm-file-name-replace-whitespace (file-name)
+ "Replace whitespace characters in FILE-NAME with underscores.
+Set `mm-file-name-replace-whitespace' to any other string if you do not
+like underscores."
+ (let ((s (or mm-file-name-replace-whitespace "_")))
+ (while (string-match "\\s-" file-name)
+ (setq file-name (replace-match s t t file-name))))
+ file-name)
(defun mm-save-part (handle)
"Write HANDLE to a file."
(mm-handle-disposition handle) 'filename))
file)
(when filename
- (setq filename (file-name-nondirectory filename)))
+ (setq filename (gnus-map-function mm-file-name-rewrite-functions
+ (file-name-nondirectory filename))))
(setq file
(read-file-name "Save MIME part to: "
(expand-file-name
(read-string "Shell command on MIME part: " mm-last-shell-command)))
(mm-with-unibyte-buffer
(mm-insert-part handle)
- (shell-command-on-region (point-min) (point-max) command nil))))
+ (let ((coding-system-for-write 'binary))
+ (shell-command-on-region (point-min) (point-max) command nil)))))
(defun mm-interactively-view-part (handle)
"Display HANDLE using METHOD."
"Return the handle(s) referred to by ID."
(cdr (assoc id mm-content-id-alist)))
+(defconst mm-image-type-regexps
+ '(("/\\*.*XPM.\\*/" . xpm)
+ ("P[1-6]" . pbm)
+ ("GIF8" . gif)
+ ("\377\330" . jpeg)
+ ("\211PNG\r\n" . png)
+ ("#define" . xbm)
+ ("\\(MM\0\\*\\)\\|\\(II\\*\0\\)" . tiff)
+ ("%!PS" . postscript))
+ "Alist of (REGEXP . IMAGE-TYPE) pairs used to auto-detect image types.
+When the first bytes of an image file match REGEXP, it is assumed to
+be of image type IMAGE-TYPE.")
+
+;; Steal from image.el. image-type-from-data suffers multi-line matching bug.
+(defun mm-image-type-from-buffer ()
+ "Determine the image type from data in the current buffer.
+Value is a symbol specifying the image type or nil if type cannot
+be determined."
+ (let ((types mm-image-type-regexps)
+ type)
+ (goto-char (point-min))
+ (while (and types (null type))
+ (let ((regexp (car (car types)))
+ (image-type (cdr (car types))))
+ (when (looking-at regexp)
+ (setq type image-type))
+ (setq types (cdr types))))
+ type))
+
(defun mm-get-image (handle)
"Return an image instance based on HANDLE."
(let ((type (mm-handle-media-subtype handle))
(prog1
(setq spec
(ignore-errors
- ;; Avoid testing `make-glyph' since W3 may define
- ;; a bogus version of it.
+ ;; Avoid testing `make-glyph' since W3 may define
+ ;; a bogus version of it.
(if (fboundp 'create-image)
- (create-image (buffer-string) (intern type) 'data-p)
- (cond
- ((equal type "xbm")
- ;; xbm images require special handling, since
- ;; the only way to create glyphs from these
- ;; (without a ton of work) is to write them
- ;; out to a file, and then create a file
- ;; specifier.
- (let ((file (make-temp-name
- (expand-file-name "emm.xbm"
- mm-tmp-directory))))
- (unwind-protect
- (progn
- (write-region (point-min) (point-max) file)
- (make-glyph (list (cons 'x file))))
- (ignore-errors
- (delete-file file)))))
- (t
- (make-glyph
- (vector (intern type) :data (buffer-string))))))))
+ (create-image (buffer-string)
+ (or (mm-image-type-from-buffer)
+ (intern type))
+ 'data-p)
+ (mm-create-image-xemacs type))))
(mm-handle-set-cache handle spec))))))
+(defun mm-create-image-xemacs (type)
+ (cond
+ ((equal type "xbm")
+ ;; xbm images require special handling, since
+ ;; the only way to create glyphs from these
+ ;; (without a ton of work) is to write them
+ ;; out to a file, and then create a file
+ ;; specifier.
+ (let ((file (make-temp-name
+ (expand-file-name "emm.xbm"
+ mm-tmp-directory))))
+ (unwind-protect
+ (progn
+ (write-region (point-min) (point-max) file)
+ (make-glyph (list (cons 'x file))))
+ (ignore-errors
+ (delete-file file)))))
+ (t
+ (make-glyph
+ (vector
+ (or (mm-image-type-from-buffer)
+ (intern type))
+ :data (buffer-string))))))
+
(defun mm-image-fit-p (handle)
"Say whether the image in HANDLE will fit the current window."
(let ((image (mm-get-image handle)))
(car handle))))
(defun mm-possibly-verify-or-decrypt (parts ctl)
- (let ((subtype (cadr (split-string (car ctl) "/")))
+ (let ((type (car ctl))
+ (subtype (cadr (split-string (car ctl) "/")))
(mm-security-handle ctl) ;; (car CTL) is the type.
protocol func functest)
(cond
+ ((or (equal type "application/x-pkcs7-mime")
+ (equal type "application/pkcs7-mime"))
+ (with-temp-buffer
+ (when (and (cond
+ ((eq mm-decrypt-option 'never) nil)
+ ((eq mm-decrypt-option 'always) t)
+ ((eq mm-decrypt-option 'known) t)
+ (t (y-or-n-p
+ (format "Decrypt (S/MIME) part? "))))
+ (mm-view-pkcs7 parts))
+ (setq parts (mm-dissect-buffer t)))))
((equal subtype "signed")
(unless (and (setq protocol
(mm-handle-multipart-ctl-parameter ctl 'protocol))
parts))
(defun mm-multiple-handles (handles)
- (and (listp (car handles))
- (> (length handles) 1)))
+ (and (listp (car handles))
+ (> (length handles) 1)))
-(defun mm-merge-handles (handles1 handles2)
+(defun mm-merge-handles (handles1 handles2)
(append
- (if (listp (car handles1))
+ (if (listp (car handles1))
handles1
(list handles1))
(if (listp (car handles2))
handles2
(list handles2))))
+(defun mm-readable-p (handle)
+ "Say whether the content of HANDLE is readable."
+ (and (< (with-current-buffer (mm-handle-buffer handle)
+ (buffer-size)) 10000)
+ (mm-with-unibyte-buffer
+ (mm-insert-part handle)
+ (and (eq (mm-body-7-or-8) '7bit)
+ (not (mm-long-lines-p 76))))))
+
(provide 'mm-decode)
;;; mm-decode.el ends here
-;;; mm-encode.el --- Functions for encoding MIME things
+;;; mm-encode.el --- Functions for encoding MIME things
;; Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
("message/rfc822" 8bit)
("application/emacs-lisp" 8bit)
("application/x-patch" 8bit)
- (".*" qp-or-base64))
+ (".*" base64))
"Alist of regexps that match MIME types and their encodings.
If the encoding is `qp-or-base64', then either quoted-printable
or base64 will be used, depending on what is more efficient.")
((functionp encoding)
(ignore-errors (funcall encoding (point-min) (point-max))))
(t
- (message "Unknown encoding %s; defaulting to 8bit" encoding))))
+ (message "Unknown encoding %s; treating it as 8bit" encoding))))
(defun mm-encode-buffer (type)
"Encode the buffer which contains data of TYPE.
(bits (mm-body-7-or-8)))
;; We force buffers that are 7bit to be unencoded, no matter
;; what the preferred encoding is.
- (when (eq bits '7bit)
+ ;; Only if the buffers don't contain lone lines.
+ (when (and (eq bits '7bit) (not (mm-long-lines-p 76)))
(setq encoding bits))
(mm-encode-content-transfer-encoding encoding mime-type)
encoding))
(while rules
(when (string-match (caar rules) type)
(throw 'found
- (let ((encoding
+ (let ((encoding
(if (eq (cadr (car rules)) 'qp-or-base64)
(mm-qp-or-base64)
(cadr (car rules)))))
;;; Code:
-(eval-when-compile
- (require 'cl))
+(eval-when-compile (require 'cl))
(require 'mm-util)
(require 'mm-decode)
+(require 'mm-url)
(defvar mm-extern-function-alist
'((local-file . mm-extern-local-file)
(let ((name (cdr (assq 'name (cdr (mm-handle-type handle)))))
(coding-system-for-read mm-binary-coding-system))
(unless name
- (error "The filename is not specified."))
+ (error "The filename is not specified"))
(mm-disable-multibyte-mule4)
(if (file-exists-p name)
(mm-insert-file-contents name nil nil nil nil t)
- (error (format "File %s is gone." name)))))
+ (error (format "File %s is gone" name)))))
(defun mm-extern-url (handle)
(erase-buffer)
- (require 'url)
(let ((url (cdr (assq 'url (cdr (mm-handle-type handle)))))
(name buffer-file-name)
(coding-system-for-read mm-binary-coding-system))
(unless url
- (error "URL is not specified."))
+ (error "URL is not specified"))
(mm-with-unibyte-current-buffer-mule4
- (url-insert-file-contents url))
+ (mm-url-insert-file-contents url))
(mm-disable-multibyte-mule4)
(setq buffer-file-name name)))
"@" site ":" directory "/" name))
(coding-system-for-read mm-binary-coding-system))
(unless name
- (error "The filename is not specified."))
+ (error "The filename is not specified"))
(mm-disable-multibyte-mule4)
(mm-insert-file-contents path nil nil nil nil t)))
(func (cdr (assq (intern
(downcase
(or access-type
- (error "Couldn't find access type."))))
+ (error "Couldn't find access type"))))
mm-extern-function-alist)))
gnus-displaying-mime buf
handles)
(unless (mm-handle-cache handle)
(unless func
- (error (format "Access type (%s) is not supported." access-type)))
+ (error (format "Access type (%s) is not supported" access-type)))
(with-temp-buffer
(mm-insert-part handle)
(goto-char (point-max))
(setq handles (mm-dissect-buffer t)))
(unless (bufferp (car handles))
(mm-destroy-parts handles)
- (error "Multipart external body is not supported."))
+ (error "Multipart external body is not supported"))
(save-excursion ;; single part
(set-buffer (setq buf (mm-handle-buffer handles)))
(let (good)
(error nil))
(delete-region ,(point-min-marker) ,(point-max-marker))))))))))
-;; mm-extern.el ends here
+(provide 'mm-extern)
+
+;;; mm-extern.el ends here
;;; Code:
-(eval-when-compile
- (require 'cl))
+(eval-when-compile (require 'cl))
(require 'gnus-sum)
(require 'mm-util)
gnus-displaying-mime handles buffer)
(unless (mm-handle-cache handle)
(unless id
- (error "Can not find message/partial id."))
+ (error "Can not find message/partial id"))
(setq phandles
(sort (cons handle
(mm-partial-find-parts
(if ntotal
(if total
(unless (eq total ntotal)
- (error "The numbers of total are different."))
+ (error "The numbers of total are different"))
(setq total ntotal)))
(unless (< nn n)
(unless (eq nn n)
(error nil))
(delete-region ,(point-min-marker) ,(point-max-marker))))))))))
-;; mm-partial.el ends here
+(provide 'mm-partial)
+
+;;; mm-partial.el ends here
--- /dev/null
+;;; mm-url.el --- a wrapper of url functions/commands for Gnus
+;; Copyright (C) 2001 Free Software Foundation, Inc.
+
+;; Author: Shenghuo Zhu <zsh@cs.rochester.edu>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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 2, or (at your
+;; option) any later version.
+
+;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; Some codes are stolen from w3 and url packages. Some are moved from
+;; nnweb.
+
+;; TODO: Support POST, cookie.
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'mm-util)
+
+(eval-and-compile
+ (autoload 'executable-find "executable")
+ (autoload 'url-insert-file-contents "url-handlers"))
+
+(defgroup mm-url nil
+ "A wrapper of url package and external url command for Gnus."
+ :group 'gnus)
+
+(defcustom mm-url-use-external (not
+ (condition-case nil
+ (require 'url-handlers)
+ (error nil)))
+ "*If not-nil, use external grab program `mm-url-program'."
+ :type 'boolean
+ :group 'mm-url)
+
+(defvar mm-url-predefined-programs
+ '((wget "wget" "-q" "-O" "-")
+ (lynx "lynx" "-source")
+ (curl "curl")))
+
+(defcustom mm-url-program
+ (cond
+ ((executable-find "wget") 'wget)
+ ((executable-find "lynx") 'lynx)
+ ((executable-find "curl") 'curl)
+ (t "GET"))
+ "The url grab program."
+ :type '(choice
+ (symbol :tag "wget" wget)
+ (symbol :tag "lynx" lynx)
+ (symbol :tag "curl" curl)
+ (string :tag "other"))
+ :group 'mm-url)
+
+(defcustom mm-url-arguments nil
+ "The arguments for `mm-url-program'."
+ :type '(repeat string)
+ :group 'mm-url)
+
+;; Stolen from w3.
+(defvar mm-url-html-entities
+ '(
+ ;;(excl . 33)
+ (quot . 34)
+ ;;(num . 35)
+ ;;(dollar . 36)
+ ;;(percent . 37)
+ (amp . 38)
+ (rsquo . 39) ; should be U+8217
+ ;;(apos . 39)
+ ;;(lpar . 40)
+ ;;(rpar . 41)
+ ;;(ast . 42)
+ ;;(plus . 43)
+ ;;(comma . 44)
+ ;;(period . 46)
+ ;;(colon . 58)
+ ;;(semi . 59)
+ (lt . 60)
+ ;;(equals . 61)
+ (gt . 62)
+ ;;(quest . 63)
+ ;;(commat . 64)
+ ;;(lsqb . 91)
+ ;;(rsqb . 93)
+ (uarr . 94) ; should be U+8593
+ ;;(lowbar . 95)
+ (lsquo . 96) ; should be U+8216
+ (lcub . 123)
+ ;;(verbar . 124)
+ (rcub . 125)
+ (tilde . 126)
+ (nbsp . 160)
+ (iexcl . 161)
+ (cent . 162)
+ (pound . 163)
+ (curren . 164)
+ (yen . 165)
+ (brvbar . 166)
+ (sect . 167)
+ (uml . 168)
+ (copy . 169)
+ (ordf . 170)
+ (laquo . 171)
+ (not . 172)
+ (shy . 173)
+ (reg . 174)
+ (macr . 175)
+ (deg . 176)
+ (plusmn . 177)
+ (sup2 . 178)
+ (sup3 . 179)
+ (acute . 180)
+ (micro . 181)
+ (para . 182)
+ (middot . 183)
+ (cedil . 184)
+ (sup1 . 185)
+ (ordm . 186)
+ (raquo . 187)
+ (frac14 . 188)
+ (frac12 . 189)
+ (frac34 . 190)
+ (iquest . 191)
+ (Agrave . 192)
+ (Aacute . 193)
+ (Acirc . 194)
+ (Atilde . 195)
+ (Auml . 196)
+ (Aring . 197)
+ (AElig . 198)
+ (Ccedil . 199)
+ (Egrave . 200)
+ (Eacute . 201)
+ (Ecirc . 202)
+ (Euml . 203)
+ (Igrave . 204)
+ (Iacute . 205)
+ (Icirc . 206)
+ (Iuml . 207)
+ (ETH . 208)
+ (Ntilde . 209)
+ (Ograve . 210)
+ (Oacute . 211)
+ (Ocirc . 212)
+ (Otilde . 213)
+ (Ouml . 214)
+ (times . 215)
+ (Oslash . 216)
+ (Ugrave . 217)
+ (Uacute . 218)
+ (Ucirc . 219)
+ (Uuml . 220)
+ (Yacute . 221)
+ (THORN . 222)
+ (szlig . 223)
+ (agrave . 224)
+ (aacute . 225)
+ (acirc . 226)
+ (atilde . 227)
+ (auml . 228)
+ (aring . 229)
+ (aelig . 230)
+ (ccedil . 231)
+ (egrave . 232)
+ (eacute . 233)
+ (ecirc . 234)
+ (euml . 235)
+ (igrave . 236)
+ (iacute . 237)
+ (icirc . 238)
+ (iuml . 239)
+ (eth . 240)
+ (ntilde . 241)
+ (ograve . 242)
+ (oacute . 243)
+ (ocirc . 244)
+ (otilde . 245)
+ (ouml . 246)
+ (divide . 247)
+ (oslash . 248)
+ (ugrave . 249)
+ (uacute . 250)
+ (ucirc . 251)
+ (uuml . 252)
+ (yacute . 253)
+ (thorn . 254)
+ (yuml . 255)
+
+ ;; Special handling of these
+ (frac56 . "5/6")
+ (frac16 . "1/6")
+ (frac45 . "4/5")
+ (frac35 . "3/5")
+ (frac25 . "2/5")
+ (frac15 . "1/5")
+ (frac23 . "2/3")
+ (frac13 . "1/3")
+ (frac78 . "7/8")
+ (frac58 . "5/8")
+ (frac38 . "3/8")
+ (frac18 . "1/8")
+
+ ;; The following 5 entities are not mentioned in the HTML 2.0
+ ;; standard, nor in any other HTML proposed standard of which I
+ ;; am aware. I am not even sure they are ISO entity names. ***
+ ;; Hence, some arrangement should be made to give a bad HTML
+ ;; message when they are seen.
+ (ndash . 45)
+ (mdash . 45)
+ (emsp . 32)
+ (ensp . 32)
+ (sim . 126)
+ (le . "<=")
+ (agr . "alpha")
+ (rdquo . "''")
+ (ldquo . "``")
+ (trade . "(TM)")
+ ;; To be done
+ ;; (shy . ????) ; soft hyphen
+ )
+ "*An assoc list of entity names and how to actually display them.")
+
+(defconst mm-url-unreserved-chars
+ '(
+ ?a ?b ?c ?d ?e ?f ?g ?h ?i ?j ?k ?l ?m ?n ?o ?p ?q ?r ?s ?t ?u ?v ?w ?x ?y ?z
+ ?A ?B ?C ?D ?E ?F ?G ?H ?I ?J ?K ?L ?M ?N ?O ?P ?Q ?R ?S ?T ?U ?V ?W ?X ?Y ?Z
+ ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9
+ ?- ?_ ?. ?! ?~ ?* ?' ?\( ?\))
+ "A list of characters that are _NOT_ reserved in the URL spec.
+This is taken from RFC 2396.")
+
+(defun mm-url-insert-file-contents (url)
+ (if mm-url-use-external
+ (if (string-match "^file:/+" url)
+ (insert-file-contents (substring url (1- (match-end 0))))
+ (mm-url-insert-file-contents-external url))
+ (require 'url-handlers)
+ (let ((name buffer-file-name))
+ (prog1
+ (url-insert-file-contents url)
+ (setq buffer-file-name name)))))
+
+(defun mm-url-insert-file-contents-external (url)
+ (let (program args)
+ (if (symbolp mm-url-program)
+ (let ((item (cdr (assq mm-url-program mm-url-predefined-programs))))
+ (setq program (car item)
+ args (append (cdr item) (list url))))
+ (setq program mm-url-program
+ args (append mm-url-arguments (list url))))
+ (apply 'call-process program nil t nil args)))
+
+(defun mm-url-insert (url &optional follow-refresh)
+ "Insert the contents from an URL in the current buffer.
+If FOLLOW-REFRESH is non-nil, redirect refresh url in META."
+ (if follow-refresh
+ (save-restriction
+ (narrow-to-region (point) (point))
+ (mm-url-insert-file-contents url)
+ (goto-char (point-min))
+ (when (re-search-forward
+ "<meta[ \t\r\n]*http-equiv=\"Refresh\"[^>]*URL=\\([^\"]+\\)\"" nil t)
+ (let ((url (match-string 1)))
+ (delete-region (point-min) (point-max))
+ (mm-url-insert url t))))
+ (mm-url-insert-file-contents url)))
+
+(defun mm-url-decode-entities ()
+ "Decode all HTML entities."
+ (goto-char (point-min))
+ (while (re-search-forward "&\\(#[0-9]+\\|[a-z]+\\);" nil t)
+ (let ((elem (if (eq (aref (match-string 1) 0) ?\#)
+ (let ((c
+ (string-to-number (substring
+ (match-string 1) 1))))
+ (if (mm-char-or-char-int-p c) c 32))
+ (or (cdr (assq (intern (match-string 1))
+ mm-url-html-entities))
+ ?#))))
+ (unless (stringp elem)
+ (setq elem (char-to-string elem)))
+ (replace-match elem t t))))
+
+(defun mm-url-decode-entities-nbsp ()
+ "Decode all HTML entities and to a space."
+ (let ((mm-url-html-entities (cons '(nbsp . 32) mm-url-html-entities)))
+ (mm-url-decode-entities)))
+
+(defun mm-url-decode-entities-string (string)
+ (with-temp-buffer
+ (insert string)
+ (mm-url-decode-entities)
+ (buffer-substring (point-min) (point-max))))
+
+(defun mm-url-form-encode-xwfu (chunk)
+ "Escape characters in a string for application/x-www-form-urlencoded.
+Blasphemous crap because someone didn't think %20 was good enough for encoding
+spaces. Die Die Die."
+ ;; This will get rid of the 'attributes' specified by the file type,
+ ;; which are useless for an application/x-www-form-urlencoded form.
+ (if (consp chunk)
+ (setq chunk (cdr chunk)))
+
+ (mapconcat
+ (lambda (char)
+ (cond
+ ((= char ? ) "+")
+ ((memq char mm-url-unreserved-chars) (char-to-string char))
+ (t (upcase (format "%%%02x" char)))))
+ ;; Fixme: Should this actually be accepting multibyte? Is there a
+ ;; better way in XEmacs?
+ (if (featurep 'mule)
+ (encode-coding-string chunk
+ (if (fboundp 'find-coding-systems-string)
+ (car (find-coding-systems-string chunk))
+ buffer-file-coding-system))
+ chunk)
+ ""))
+
+(defun mm-url-encode-www-form-urlencoded (pairs)
+ "Return PAIRS encoded for forms."
+ (mapconcat
+ (lambda (data)
+ (concat (mm-url-form-encode-xwfu (car data)) "="
+ (mm-url-form-encode-xwfu (cdr data))))
+ pairs "&"))
+
+(defun mm-url-fetch-form (url pairs)
+ "Fetch a form from URL with PAIRS as the data using the POST method."
+ (require 'url-handlers)
+ (let ((url-request-data (mm-url-encode-www-form-urlencoded pairs))
+ (url-request-method "POST")
+ (url-request-extra-headers
+ '(("Content-type" . "application/x-www-form-urlencoded"))))
+ (url-insert-file-contents url)
+ (setq buffer-file-name nil))
+ t)
+
+(defun mm-url-fetch-simple (url content)
+ (require 'url-handlers)
+ (let ((url-request-data content)
+ (url-request-method "POST")
+ (url-request-extra-headers
+ '(("Content-type" . "application/x-www-form-urlencoded"))))
+ (url-insert-file-contents url)
+ (setq buffer-file-name nil))
+ t)
+
+(defun mm-url-remove-markup ()
+ "Remove all HTML markup, leaving just plain text."
+ (goto-char (point-min))
+ (while (search-forward "<!--" nil t)
+ (delete-region (match-beginning 0)
+ (or (search-forward "-->" nil t)
+ (point-max))))
+ (goto-char (point-min))
+ (while (re-search-forward "<[^>]+>" nil t)
+ (replace-match "" t t)))
+
+(provide 'mm-url)
+
+;;; mm-url.el ends here
(eval-when-compile (require 'cl))
(require 'mail-prsvr)
-(defvar mm-mime-mule-charset-alist
- `((us-ascii ascii)
- (iso-8859-1 latin-iso8859-1)
- (iso-8859-2 latin-iso8859-2)
- (iso-8859-3 latin-iso8859-3)
- (iso-8859-4 latin-iso8859-4)
- (iso-8859-5 cyrillic-iso8859-5)
- ;; Non-mule (X)Emacs uses the last mule-charset for 8bit characters.
- ;; The fake mule-charset, gnus-koi8-r, tells Gnus that the default
- ;; charset is koi8-r, not iso-8859-5.
- (koi8-r cyrillic-iso8859-5 gnus-koi8-r)
- (iso-8859-6 arabic-iso8859-6)
- (iso-8859-7 greek-iso8859-7)
- (iso-8859-8 hebrew-iso8859-8)
- (iso-8859-9 latin-iso8859-9)
- (iso-8859-14 latin-iso8859-14)
- (iso-8859-15 latin-iso8859-15)
- (viscii vietnamese-viscii-lower)
- (iso-2022-jp latin-jisx0201 japanese-jisx0208 japanese-jisx0208-1978)
- (euc-kr korean-ksc5601)
- (gb2312 chinese-gb2312)
- (big5 chinese-big5-1 chinese-big5-2)
- (tibetan tibetan)
- (thai-tis620 thai-tis620)
- (iso-2022-7bit ethiopic arabic-1-column arabic-2-column)
- (iso-2022-jp-2 latin-iso8859-1 greek-iso8859-7
- latin-jisx0201 japanese-jisx0208-1978
- chinese-gb2312 japanese-jisx0208
- korean-ksc5601 japanese-jisx0212
- katakana-jisx0201)
- (iso-2022-int-1 latin-iso8859-1 greek-iso8859-7
- latin-jisx0201 japanese-jisx0208-1978
- chinese-gb2312 japanese-jisx0208
- korean-ksc5601 japanese-jisx0212
- chinese-cns11643-1 chinese-cns11643-2)
- (iso-2022-int-1 latin-iso8859-1 latin-iso8859-2
- cyrillic-iso8859-5 greek-iso8859-7
- latin-jisx0201 japanese-jisx0208-1978
- chinese-gb2312 japanese-jisx0208
- korean-ksc5601 japanese-jisx0212
- chinese-cns11643-1 chinese-cns11643-2
- chinese-cns11643-3 chinese-cns11643-4
- chinese-cns11643-5 chinese-cns11643-6
- chinese-cns11643-7)
- ,(if (or (not (fboundp 'charsetp)) ;; non-Mule case
- (not (fboundp 'coding-system-p))
- (charsetp 'unicode-a)
- (not (coding-system-p 'mule-utf-8)))
- '(utf-8 unicode-a unicode-b unicode-c unicode-d unicode-e)
- ;; If we have utf-8 we're in Mule 5+.
- (delete 'ascii (coding-system-get 'mule-utf-8 'safe-charsets))))
- "Alist of MIME-charset/MULE-charsets.")
-
(eval-and-compile
(mapcar
(lambda (elem)
(make-char
. (lambda (charset int)
(int-to-char int)))
- (read-coding-system
- . (lambda (prompt)
- "Prompt the user for a coding system."
- (completing-read
- prompt (mapcar (lambda (s) (list (symbol-name (car s))))
- mm-mime-mule-charset-alist))))
(read-charset
. (lambda (prompt)
"Return a charset."
(subst-char-in-string
. (lambda (from to string) ;; stolen (and renamed) from nnheader.el
"Replace characters in STRING from FROM to TO."
- (let ((string (substring string 0)) ;Copy string.
+ (let ((string (substring string 0)) ;Copy string.
(len (length string))
(idx 0))
;; Replace all occurrences of FROM with TO.
(setq idx (1+ idx)))
string)))
(string-as-unibyte . identity)
+ (string-as-multibyte . identity)
(multibyte-string-p . ignore))))
(eval-and-compile
((fboundp 'char-valid-p) 'char-valid-p)
(t 'identity))))
+(eval-and-compile
+ (defalias 'mm-read-coding-system
+ (cond
+ ((fboundp 'read-coding-system)
+ (if (and (featurep 'xemacs)
+ (<= (string-to-number emacs-version) 21.1))
+ (lambda (prompt &optional default-coding-system)
+ (read-coding-system prompt))
+ 'read-coding-system))
+ (t (lambda (prompt &optional default-coding-system)
+ "Prompt the user for a coding system."
+ (completing-read
+ prompt (mapcar (lambda (s) (list (symbol-name (car s))))
+ mm-mime-mule-charset-alist)))))))
+
(defvar mm-coding-system-list nil)
(defun mm-get-coding-system-list ()
"Get the coding system list."
(memq sym (mm-get-coding-system-list))))
(defvar mm-charset-synonym-alist
- `((big5 . cn-big5)
- (gb2312 . cn-gb-2312)
- (cn-gb . cn-gb-2312)
+ `(
+ ;; Perfectly fine? A valid MIME name, anyhow.
+ ,@(unless (mm-coding-system-p 'big5)
+ '((big5 . cn-big5)))
+ ;; Not in XEmacs, but it's not a proper MIME charset anyhow.
+ ,@(unless (mm-coding-system-p 'x-ctext)
+ '((x-ctext . ctext)))
+ ;; Apparently not defined in Emacs 20, but is a valid MIME name.
+ ,@(unless (mm-coding-system-p 'gb2312)
+ '((gb2312 . cn-gb-2312)))
+ ;; ISO-8859-15 is very similar to ISO-8859-1.
+ ,@(unless (mm-coding-system-p 'iso-8859-15) ; Emacs 21 defines it.
+ '((iso-8859-15 . iso-8859-1)))
;; Windows-1252 is actually a superset of Latin-1. See also
;; `gnus-article-dumbquotes-map'.
- ,(unless (mm-coding-system-p 'windows-1252) ; should be defined eventually
- '(windows-1252 . iso-8859-1))
- (x-ctext . ctext))
+ ,@(unless (mm-coding-system-p 'windows-1252)
+ (if (mm-coding-system-p 'cp1252)
+ '((windows-1252 . cp1252))
+ '((windows-1252 . iso-8859-1))))
+ ;; Windows-1250 is a variant of Latin-2 heavily used by Microsoft
+ ;; Outlook users in Czech republic. Use this to allow reading of their
+ ;; e-mails. cp1250 should be defined by M-x codepage-setup.
+ ,@(if (and (not (mm-coding-system-p 'windows-1250))
+ (mm-coding-system-p 'cp1250))
+ '((windows-1250 . cp1250)))
+ )
"A mapping from invalid charset names to the real charset names.")
(defvar mm-binary-coding-system
(t mm-binary-coding-system))
"Coding system of auto save file.")
+(defvar mm-universal-coding-system mm-auto-save-coding-system
+ "The universal coding system.")
+
+;; Fixme: some of the cars here aren't valid MIME charsets. That
+;; should only matter with XEmacs, though.
+(defvar mm-mime-mule-charset-alist
+ `((us-ascii ascii)
+ (iso-8859-1 latin-iso8859-1)
+ (iso-8859-2 latin-iso8859-2)
+ (iso-8859-3 latin-iso8859-3)
+ (iso-8859-4 latin-iso8859-4)
+ (iso-8859-5 cyrillic-iso8859-5)
+ ;; Non-mule (X)Emacs uses the last mule-charset for 8bit characters.
+ ;; The fake mule-charset, gnus-koi8-r, tells Gnus that the default
+ ;; charset is koi8-r, not iso-8859-5.
+ (koi8-r cyrillic-iso8859-5 gnus-koi8-r)
+ (iso-8859-6 arabic-iso8859-6)
+ (iso-8859-7 greek-iso8859-7)
+ (iso-8859-8 hebrew-iso8859-8)
+ (iso-8859-9 latin-iso8859-9)
+ (iso-8859-14 latin-iso8859-14)
+ (iso-8859-15 latin-iso8859-15)
+ (viscii vietnamese-viscii-lower)
+ (iso-2022-jp latin-jisx0201 japanese-jisx0208 japanese-jisx0208-1978)
+ (euc-kr korean-ksc5601)
+ (gb2312 chinese-gb2312)
+ (big5 chinese-big5-1 chinese-big5-2)
+ (tibetan tibetan)
+ (thai-tis620 thai-tis620)
+ (iso-2022-7bit ethiopic arabic-1-column arabic-2-column)
+ (iso-2022-jp-2 latin-iso8859-1 greek-iso8859-7
+ latin-jisx0201 japanese-jisx0208-1978
+ chinese-gb2312 japanese-jisx0208
+ korean-ksc5601 japanese-jisx0212
+ katakana-jisx0201)
+ (iso-2022-int-1 latin-iso8859-1 greek-iso8859-7
+ latin-jisx0201 japanese-jisx0208-1978
+ chinese-gb2312 japanese-jisx0208
+ korean-ksc5601 japanese-jisx0212
+ chinese-cns11643-1 chinese-cns11643-2)
+ (iso-2022-int-1 latin-iso8859-1 latin-iso8859-2
+ cyrillic-iso8859-5 greek-iso8859-7
+ latin-jisx0201 japanese-jisx0208-1978
+ chinese-gb2312 japanese-jisx0208
+ korean-ksc5601 japanese-jisx0212
+ chinese-cns11643-1 chinese-cns11643-2
+ chinese-cns11643-3 chinese-cns11643-4
+ chinese-cns11643-5 chinese-cns11643-6
+ chinese-cns11643-7)
+ ,(if (or (not (fboundp 'charsetp)) ;; non-Mule case
+ (charsetp 'unicode-a)
+ (not (mm-coding-system-p 'mule-utf-8)))
+ '(utf-8 unicode-a unicode-b unicode-c unicode-d unicode-e)
+ ;; If we have utf-8 we're in Mule 5+.
+ (append '(utf-8)
+ (delete 'ascii
+ (coding-system-get 'mule-utf-8 'safe-charsets)))))
+ "Alist of MIME-charset/MULE-charsets.")
+
+;; Correct by construction, but should be unnecessary:
+;; XEmacs hates it.
+(when (and (not (featurep 'xemacs))
+ (fboundp 'coding-system-list)
+ (fboundp 'sort-coding-systems))
+ (setq mm-mime-mule-charset-alist
+ (apply
+ 'nconc
+ (mapcar
+ (lambda (cs)
+ (when (and (coding-system-get cs 'mime-charset)
+ (not (eq t (coding-system-get cs 'safe-charsets))))
+ (list (cons (coding-system-get cs 'mime-charset)
+ (delq 'ascii
+ (coding-system-get cs 'safe-charsets))))))
+ (sort-coding-systems (coding-system-list 'base-only))))))
+
+(defvar mm-hack-charsets '(iso-8859-15 iso-2022-jp-2)
+ "A list of special charsets.
+Valid elements include:
+`iso-8859-15' convert ISO-8859-1, -9 to ISO-8859-15 if ISO-8859-15 exists.
+`iso-2022-jp-2' convert ISO-2022-jp to ISO-2022-jp-2 if ISO-2022-jp-2 exists."
+)
+
+(defvar mm-iso-8859-15-compatible
+ '((iso-8859-1 "\xA4\xA6\xA8\xB4\xB8\xBC\xBD\xBE")
+ (iso-8859-9 "\xA4\xA6\xA8\xB4\xB8\xBC\xBD\xBE\xD0\xDD\xDE\xF0\xFD\xFE"))
+ "ISO-8859-15 exchangeable coding systems and inconvertible characters.")
+
+(defvar mm-iso-8859-x-to-15-table
+ (and (fboundp 'coding-system-p)
+ (mm-coding-system-p 'iso-8859-15)
+ (mapcar
+ (lambda (cs)
+ (if (mm-coding-system-p (car cs))
+ (let ((c (string-to-char
+ (decode-coding-string "\341" (car cs)))))
+ (cons (char-charset c)
+ (cons
+ (- (string-to-char
+ (decode-coding-string "\341" 'iso-8859-15)) c)
+ (string-to-list (decode-coding-string (car (cdr cs))
+ (car cs))))))
+ '(gnus-charset 0)))
+ mm-iso-8859-15-compatible))
+ "A table of the difference character between ISO-8859-X and ISO-8859-15.")
+
+(defvar mm-coding-system-priorities nil
+ "Preferred coding systems for encoding outgoing mails.
+
+More than one suitable coding systems may be found for some texts. By
+default, a coding system with the highest priority is used to encode
+outgoing mails (see `sort-coding-systems'). If this variable is set,
+it overrides the default priority. For example, Japanese users may
+prefer iso-2022-jp to japanese-shift-jis:
+
+\(setq mm-coding-system-priorities
+ '(iso-2022-jp iso-2022-jp-2 japanese-shift-jis utf-8))
+")
+
;;; Internal variables:
;;; Functions:
(defun mm-mule-charset-to-mime-charset (charset)
"Return the MIME charset corresponding to the given Mule CHARSET."
- (let ((alist mm-mime-mule-charset-alist)
- out)
- (while alist
- (when (memq charset (cdar alist))
- (setq out (caar alist)
- alist nil))
- (pop alist))
- out))
+ (if (fboundp 'find-coding-systems-for-charsets)
+ (let (mime)
+ (dolist (cs (find-coding-systems-for-charsets (list charset)))
+ (unless mime
+ (when cs
+ (setq mime (coding-system-get cs 'mime-charset)))))
+ mime)
+ (let ((alist mm-mime-mule-charset-alist)
+ out)
+ (while alist
+ (when (memq charset (cdar alist))
+ (setq out (caar alist)
+ alist nil))
+ (pop alist))
+ out)))
(defun mm-charset-to-coding-system (charset &optional lbt)
"Return coding-system corresponding to CHARSET.
used as the line break code type of the coding system."
(when (stringp charset)
(setq charset (intern (downcase charset))))
- (setq charset
- (or (cdr (assq charset mm-charset-synonym-alist))
- charset))
(when lbt
(setq charset (intern (format "%s-%s" charset lbt))))
(cond
+ ((null charset)
+ charset)
;; Running in a non-MULE environment.
((null (mm-get-coding-system-list))
charset)
'ascii)
;; Check to see whether we can handle this charset. (This depends
;; on there being some coding system matching each `mime-charset'
- ;; coding sysytem property defined, as there should be.)
- ((memq charset (mm-get-coding-system-list))
+ ;; property defined, as there should be.)
+ ((and (mm-coding-system-p charset)
+;;; Doing this would potentially weed out incorrect charsets.
+;;; charset
+;;; (eq charset (coding-system-get charset 'mime-charset))
+ )
charset)
- ;; Nope.
- (t
- nil)))
+ ;; Translate invalid charsets.
+ ((mm-coding-system-p (setq charset
+ (cdr (assq charset
+ mm-charset-synonym-alist))))
+ charset)
+ ;; Last resort: search the coding system list for entries which
+ ;; have the right mime-charset in case the canonical name isn't
+ ;; defined (though it should be).
+ ((let (cs)
+ ;; mm-get-coding-system-list returns a list of cs without lbt.
+ ;; Do we need -lbt?
+ (dolist (c (mm-get-coding-system-list))
+ (if (and (null cs)
+ (eq charset (coding-system-get c 'mime-charset)))
+ (setq cs c)))
+ cs))))
(defsubst mm-replace-chars-in-string (string from to)
(mm-subst-char-in-string from to string))
-(defsubst mm-enable-multibyte ()
- "Set the multibyte flag of the current buffer.
+(eval-and-compile
+ (defvar mm-emacs-mule (and (not (featurep 'xemacs))
+ (boundp 'default-enable-multibyte-characters)
+ default-enable-multibyte-characters
+ (fboundp 'set-buffer-multibyte))
+ "Emacs mule.")
+
+ (defvar mm-mule4-p (and mm-emacs-mule
+ (fboundp 'charsetp)
+ (not (charsetp 'eight-bit-control)))
+ "Mule version 4.")
+
+ (if mm-emacs-mule
+ (defun mm-enable-multibyte ()
+ "Set the multibyte flag of the current buffer.
Only do this if the default value of `enable-multibyte-characters' is
non-nil. This is a no-op in XEmacs."
- (when (and (not (featurep 'xemacs))
- (boundp 'default-enable-multibyte-characters)
- default-enable-multibyte-characters
- (fboundp 'set-buffer-multibyte))
- (set-buffer-multibyte t)))
-
-(defsubst mm-disable-multibyte ()
- "Unset the multibyte flag of in the current buffer.
+ (set-buffer-multibyte t))
+ (defalias 'mm-enable-multibyte 'ignore))
+
+ (if mm-emacs-mule
+ (defun mm-disable-multibyte ()
+ "Unset the multibyte flag of in the current buffer.
This is a no-op in XEmacs."
- (when (and (not (featurep 'xemacs))
- (fboundp 'set-buffer-multibyte))
- (set-buffer-multibyte nil)))
+ (set-buffer-multibyte nil))
+ (defalias 'mm-disable-multibyte 'ignore))
-(defsubst mm-enable-multibyte-mule4 ()
- "Enable multibyte in the current buffer.
+ (if mm-mule4-p
+ (defun mm-enable-multibyte-mule4 ()
+ "Enable multibyte in the current buffer.
Only used in Emacs Mule 4."
- (when (and (not (featurep 'xemacs))
- (boundp 'default-enable-multibyte-characters)
- default-enable-multibyte-characters
- (fboundp 'set-buffer-multibyte)
- (fboundp 'charsetp)
- (not (charsetp 'eight-bit-control)))
- (set-buffer-multibyte t)))
-
-(defsubst mm-disable-multibyte-mule4 ()
- "Disable multibyte in the current buffer.
+ (set-buffer-multibyte t))
+ (defalias 'mm-enable-multibyte-mule4 'ignore))
+
+ (if mm-mule4-p
+ (defun mm-disable-multibyte-mule4 ()
+ "Disable multibyte in the current buffer.
Only used in Emacs Mule 4."
- (when (and (not (featurep 'xemacs))
- (fboundp 'set-buffer-multibyte)
- (fboundp 'charsetp)
- (not (charsetp 'eight-bit-control)))
- (set-buffer-multibyte nil)))
+ (set-buffer-multibyte nil))
+ (defalias 'mm-disable-multibyte-mule4 'ignore)))
(defun mm-preferred-coding-system (charset)
;; A typo in some Emacs versions.
- (or (get-charset-property charset 'prefered-coding-system)
- (get-charset-property charset 'preferred-coding-system)))
+ (or (get-charset-property charset 'preferred-coding-system)
+ (get-charset-property charset 'prefered-coding-system)))
(defun mm-charset-after (&optional pos)
"Return charset of a character in current buffer at position POS.
(progn
(setq mail-parse-mule-charset
(and (boundp 'current-language-environment)
- (car (last
- (assq 'charset
- (assoc current-language-environment
- language-info-alist))))))
+ (car (last
+ (assq 'charset
+ (assoc current-language-environment
+ language-info-alist))))))
(if (or (not mail-parse-mule-charset)
(eq mail-parse-mule-charset 'ascii))
(setq mail-parse-mule-charset
mail-parse-mule-charset)))))))
(defun mm-mime-charset (charset)
- "Return the MIME charset corresponding to the MULE CHARSET."
+ "Return the MIME charset corresponding to the given Mule CHARSET."
(if (eq charset 'unknown)
- (error "The message contains non-printable characters, please use attachment."))
+ (error "The message contains non-printable characters, please use attachment"))
(if (and (fboundp 'coding-system-get) (fboundp 'get-charset-property))
;; This exists in Emacs 20.
(or
(setq result (cons head result)))
(nreverse result)))
-(defun mm-find-mime-charset-region (b e)
- "Return the MIME charsets needed to encode the region between B and E."
- (let ((charsets (mapcar 'mm-mime-charset
- (delq 'ascii
- (mm-find-charset-region b e)))))
- (when (memq 'iso-2022-jp-2 charsets)
- (setq charsets (delq 'iso-2022-jp charsets)))
- (setq charsets (mm-delete-duplicates charsets))
- (if (and (> (length charsets) 1)
- (fboundp 'find-coding-systems-region)
- (let ((cs (find-coding-systems-region b e)))
- (or (memq 'utf-8 cs) (memq 'mule-utf-8 cs))))
- '(utf-8)
- charsets)))
-
+;; It's not clear whether this is supposed to mean the global or local
+;; setting. I think it's used inconsistently. -- fx
(defsubst mm-multibyte-p ()
"Say whether multibyte is enabled."
(if (and (not (featurep 'xemacs))
enable-multibyte-characters
(featurep 'mule)))
+(defun mm-iso-8859-x-to-15-region (&optional b e)
+ (if (fboundp 'char-charset)
+ (let (charset item c inconvertible)
+ (save-restriction
+ (if e (narrow-to-region b e))
+ (goto-char (point-min))
+ (skip-chars-forward "\0-\177")
+ (while (not (eobp))
+ (cond
+ ((not (setq item (assq (char-charset (setq c (char-after)))
+ mm-iso-8859-x-to-15-table)))
+ (forward-char))
+ ((memq c (cdr (cdr item)))
+ (setq inconvertible t)
+ (forward-char))
+ (t
+ (insert-before-markers (prog1 (+ c (car (cdr item)))
+ (delete-char 1))))
+ (skip-chars-forward "\0-\177"))))
+ (not inconvertible))))
+
+(defun mm-sort-coding-systems-predicate (a b)
+ (> (length (memq a mm-coding-system-priorities))
+ (length (memq b mm-coding-system-priorities))))
+
+(defun mm-find-mime-charset-region (b e &optional hack-charsets)
+ "Return the MIME charsets needed to encode the region between B and E.
+nil means ASCII, a single-element list represents an appropriate MIME
+charset, and a longer list means no appropriate charset."
+ (let (charsets)
+ ;; The return possibilities of this function are a mess...
+ (or (and (mm-multibyte-p)
+ (fboundp 'find-coding-systems-region)
+ ;; Find the mime-charset of the most preferred coding
+ ;; system that has one.
+ (let ((systems (find-coding-systems-region b e)))
+ (when mm-coding-system-priorities
+ (setq systems
+ (sort systems 'mm-sort-coding-systems-predicate)))
+ ;; Fixme: The `mime-charset' (`x-ctext') of `compound-text'
+ ;; is not in the IANA list.
+ (setq systems (delq 'compound-text systems))
+ (unless (equal systems '(undecided))
+ (while systems
+ (let ((cs (coding-system-get (pop systems) 'mime-charset)))
+ (if cs
+ (setq systems nil
+ charsets (list cs))))))
+ charsets))
+ ;; Otherwise we're not multibyte, XEmacs or a single coding
+ ;; system won't cover it.
+ (setq charsets
+ (mm-delete-duplicates
+ (mapcar 'mm-mime-charset
+ (delq 'ascii
+ (mm-find-charset-region b e))))))
+ (if (and (memq 'iso-8859-15 charsets)
+ (memq 'iso-8859-15 hack-charsets)
+ (save-excursion (mm-iso-8859-x-to-15-region b e)))
+ (mapcar (lambda (x) (setq charsets (delq (car x) charsets)))
+ mm-iso-8859-15-compatible))
+ (if (and (memq 'iso-2022-jp-2 charsets)
+ (memq 'iso-2022-jp-2 hack-charsets))
+ (setq charsets (delq 'iso-2022-jp charsets)))
+ charsets))
+
(defmacro mm-with-unibyte-buffer (&rest forms)
"Create a temporary buffer, and evaluate FORMS there like `progn'.
Use unibyte mode for this."
"Evaluate FORMS with current current buffer temporarily made unibyte.
Also bind `default-enable-multibyte-characters' to nil.
Equivalent to `progn' in XEmacs"
- (let ((buffer (make-symbol "buffer")))
- `(if (and (not (featurep 'xemacs))
- (boundp 'enable-multibyte-characters)
- enable-multibyte-characters
- (fboundp 'set-buffer-multibyte))
- (let ((,buffer (current-buffer)))
+ (let ((multibyte (make-symbol "multibyte"))
+ (buffer (make-symbol "buffer")))
+ `(if mm-emacs-mule
+ (let ((,multibyte enable-multibyte-characters)
+ (,buffer (current-buffer)))
(unwind-protect
(let (default-enable-multibyte-characters)
(set-buffer-multibyte nil)
,@forms)
(set-buffer ,buffer)
- (set-buffer-multibyte t)))
+ (set-buffer-multibyte ,multibyte)))
(let (default-enable-multibyte-characters)
,@forms))))
(put 'mm-with-unibyte-current-buffer 'lisp-indent-function 0)
(defmacro mm-with-unibyte-current-buffer-mule4 (&rest forms)
"Evaluate FORMS there like `progn' in current buffer.
Mule4 only."
- (let ((buffer (make-symbol "buffer")))
- `(if (and (not (featurep 'xemacs))
- (boundp 'enable-multibyte-characters)
- enable-multibyte-characters
- (fboundp 'set-buffer-multibyte)
- (fboundp 'charsetp)
- (not (charsetp 'eight-bit-control))) ;; For Emacs Mule 4 only.
- (let ((,buffer (current-buffer)))
- (unwind-protect
- (let (default-enable-multibyte-characters)
- (set-buffer-multibyte nil)
- ,@forms)
- (set-buffer ,buffer)
- (set-buffer-multibyte t)))
+ (let ((multibyte (make-symbol "multibyte"))
+ (buffer (make-symbol "buffer")))
+ `(if mm-mule4-p
+ (let ((,multibyte enable-multibyte-characters)
+ (,buffer (current-buffer)))
+ (unwind-protect
+ (let (default-enable-multibyte-characters)
+ (set-buffer-multibyte nil)
+ ,@forms)
+ (set-buffer ,buffer)
+ (set-buffer-multibyte ,multibyte)))
(let (default-enable-multibyte-characters)
,@forms))))
(put 'mm-with-unibyte-current-buffer-mule4 'lisp-indent-function 0)
"Return a list of Emacs charsets in the region B to E."
(cond
((and (mm-multibyte-p)
- (fboundp 'find-charset-region))
+ (fboundp 'find-charset-region))
;; Remove composition since the base charsets have been included.
;; Remove eight-bit-*, treat them as ascii.
(let ((css (find-charset-region b e)))
(mapcar (lambda (cs) (setq css (delq cs css)))
- '(composition eight-bit-control eight-bit-graphic))
+ '(composition eight-bit-control eight-bit-graphic
+ control-1))
css))
(t
;; We are in a unibyte buffer or XEmacs non-mule, so we futz around a bit.
(auto-mode-alist (if inhibit nil (mm-auto-mode-alist)))
(default-major-mode 'fundamental-mode)
(enable-local-variables nil)
- (after-insert-file-functions nil)
+ (after-insert-file-functions nil)
(enable-local-eval nil)
(find-file-hooks nil)
(inhibit-file-name-operation (if inhibit
-;;; mm-uu.el -- Return uu stuff as mm handles
+;;; mm-uu.el --- Return uu stuff as mm handles
;; Copyright (c) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
;; Author: Shenghuo Zhu <zsh@cs.rochester.edu>
;;; Commentary:
-
;;; Code:
(eval-when-compile (require 'cl))
(require 'mm-decode)
(require 'mailcap)
(require 'mml2015)
-(require 'uudecode)
-(require 'binhex)
-;; This is not the right place for this. uudecode.el should decide
-;; whether or not to use a program with a single interface, but I
-;; guess it's too late now. Also the default should depend on a test
-;; for the program. -- fx
+(autoload 'uudecode-decode-region "uudecode")
+(autoload 'uudecode-decode-region-external "uudecode")
+(autoload 'uudecode-decode-region-internal "uudecode")
+
+(autoload 'binhex-decode-region "binhex")
+(autoload 'binhex-decode-region-external "binhex")
+(autoload 'binhex-decode-region-internal "binhex")
+
(defcustom mm-uu-decode-function 'uudecode-decode-region
"*Function to uudecode.
Internal function is done in Lisp by default, therefore decoding may
appear to be horribly slow. You can make Gnus use an external
decoder, such as uudecode."
:type '(choice
- (function-item :tag "Internal" uudecode-decode-region)
+ (function-item :tag "Auto detect" uudecode-decode-region)
+ (function-item :tag "Internal" uudecode-decode-region-internal)
(function-item :tag "External" uudecode-decode-region-external))
:group 'gnus-article-mime)
Internal function is done in elisp by default, therefore decoding may
appear to be horribly slow . You can make Gnus use the external Unix
decoder, such as hexbin."
- :type '(choice (item :tag "internal" binhex-decode-region)
- (item :tag "external" binhex-decode-region-external))
+ :type '(choice (function-item :tag "Auto detect" binhex-decode-region)
+ (function-item :tag "Internal" binhex-decode-region-internal)
+ (function-item :tag "External" binhex-decode-region-external))
:group 'gnus-article-mime)
(defvar mm-uu-pgp-beginning-signature
(mm-make-handle buf
'("application/pgp-keys"))))
-;;;### autoload
+;;;###autoload
(defun mm-uu-dissect ()
"Dissect the current buffer and return a list of uu handles."
(let ((case-fold-search t)
(funcall func))
(forward-line);; in case of failure
(when (and (not (mm-uu-configure-p (mm-uu-type entry) 'disabled))
- (let ((end-regexp (mm-uu-end-regexp entry)))
+ (let ((end-regexp (mm-uu-end-regexp entry)))
(if (not end-regexp)
(or (setq end-point (point-max)) t)
(prog1
-;;; mm-view.el --- Functions for viewing MIME objects
+;;; mm-view.el --- functions for viewing MIME objects
;; Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
(autoload 'vcard-parse-string "vcard")
(autoload 'vcard-format-string "vcard")
(autoload 'fill-flowed "flow-fill")
- (autoload 'diff-mode "diff-mode"))
+ (unless (fboundp 'diff-mode)
+ (autoload 'diff-mode "diff-mode" "" t nil)))
;;;
;;; Functions for displaying various formats inline
;;;
+
(defun mm-inline-image-emacs (handle)
(let ((b (point-marker))
buffer-read-only)
`(lambda () (remove-images ,b (1+ ,b))))))
(defun mm-inline-image-xemacs (handle)
+ (insert "\n")
+ (forward-char -1)
(let ((b (point))
(annot (make-annotation (mm-get-image handle) nil 'text))
buffer-read-only)
- (insert "\n")
(mm-handle-set-undisplayer
handle
`(lambda ()
(setq text (mm-get-part handle))
(let ((b (point))
(url-standalone-mode t)
+ (w3-honor-stylesheets nil)
+ (w3-delay-image-loads t)
(url-current-object
(url-generic-parse-url (format "cid:%s" (mm-handle-id handle))))
(width (window-width))
(and (boundp 'w3-meta-charset-content-type-regexp)
(re-search-forward
w3-meta-charset-content-type-regexp nil t)))
- (setq charset (or (w3-coding-system-for-mime-charset
- (buffer-substring-no-properties
- (match-beginning 2)
- (match-end 2)))
- charset)))
+ (setq charset
+ (or (let ((bsubstr (buffer-substring-no-properties
+ (match-beginning 2)
+ (match-end 2))))
+ (if (fboundp 'w3-coding-system-for-mime-charset)
+ (w3-coding-system-for-mime-charset bsubstr)
+ (mm-charset-to-coding-system bsubstr)))
+ charset)))
(delete-region (point-min) (point-max))
(insert (mm-decode-string text charset))
(save-window-excursion
;; Don't let w3 set the global version of
;; this variable.
(fill-column fill-column)
+ (w3-honor-stylesheets nil)
+ (w3-delay-image-loads t)
(url-standalone-mode t))
(condition-case var
(w3-region (point-min) (point-max))
(error
+ (delete-region (point-min) (point-max))
+ (let ((b (point))
+ (charset (mail-content-type-get
+ (mm-handle-type handle) 'charset)))
+ (if (or (eq charset 'gnus-decoded)
+ (eq mail-parse-charset 'gnus-decoded))
+ (save-restriction
+ (narrow-to-region (point) (point))
+ (mm-insert-part handle)
+ (goto-char (point-max)))
+ (insert (mm-decode-string (mm-get-part handle)
+ charset))))
(message
"Error while rendering html; showing as text/plain"))))))
(mm-handle-set-undisplayer
'(background background-pixmap foreground)))
(delete-region ,(point-min-marker)
,(point-max-marker)))))))))
- ((or (equal type "enriched")
- (equal type "richtext"))
- (save-excursion
- (mm-with-unibyte-buffer
- (mm-insert-part handle)
- (save-window-excursion
- (enriched-decode (point-min) (point-max))
- (setq text (buffer-string)))))
- (mm-insert-inline handle text))
((equal type "x-vcard")
(mm-insert-inline
handle
(concat "\n-- \n"
- (if (fboundp 'vcard-pretty-print)
- (vcard-pretty-print (mm-get-part handle))
- (vcard-format-string
- (vcard-parse-string (mm-get-part handle)
- 'vcard-standard-filter))))))
+ (ignore-errors
+ (if (fboundp 'vcard-pretty-print)
+ (vcard-pretty-print (mm-get-part handle))
+ (vcard-format-string
+ (vcard-parse-string (mm-get-part handle)
+ 'vcard-standard-filter)))))))
(t
(let ((b (point))
(charset (mail-content-type-get
(save-restriction
(narrow-to-region b (point))
(set-text-properties (point-min) (point-max) nil)
+ (when (or (equal type "enriched")
+ (equal type "richtext"))
+ (enriched-decode (point-min) (point-max)))
(mm-handle-set-undisplayer
handle
`(lambda ()
(defun mm-w3-prepare-buffer ()
(require 'w3)
- (let ((url-standalone-mode t))
+ (let ((url-standalone-mode t)
+ (w3-honor-stylesheets nil)
+ (w3-delay-image-loads t))
(w3-prepare-buffer)))
(defun mm-view-message ()
(defun mm-display-elisp-inline (handle)
(mm-display-inline-fontify handle 'emacs-lisp-mode))
+;; id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+;; us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 }
+(defvar mm-pkcs7-signed-magic
+ (mm-string-as-unibyte
+ (apply 'concat
+ (mapcar 'char-to-string
+ (list ?\x30 ?\x5c ?\x28 ?\x80 ?\x5c ?\x7c ?\x81 ?\x2e ?\x5c
+ ?\x7c ?\x82 ?\x2e ?\x2e ?\x5c ?\x7c ?\x83 ?\x2e ?\x2e
+ ?\x2e ?\x5c ?\x29 ?\x06 ?\x09 ?\x5c ?\x2a ?\x86 ?\x48
+ ?\x86 ?\xf7 ?\x0d ?\x01 ?\x07 ?\x02)))))
+
+;; id-envelopedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+;; us(840) rsadsi(113549) pkcs(1) pkcs7(7) 3 }
+(defvar mm-pkcs7-enveloped-magic
+ (mm-string-as-unibyte
+ (apply 'concat
+ (mapcar 'char-to-string
+ (list ?\x30 ?\x5c ?\x28 ?\x80 ?\x5c ?\x7c ?\x81 ?\x2e ?\x5c
+ ?\x7c ?\x82 ?\x2e ?\x2e ?\x5c ?\x7c ?\x83 ?\x2e ?\x2e
+ ?\x2e ?\x5c ?\x29 ?\x06 ?\x09 ?\x5c ?\x2a ?\x86 ?\x48
+ ?\x86 ?\xf7 ?\x0d ?\x01 ?\x07 ?\x03)))))
+
+(defun mm-view-pkcs7-get-type (handle)
+ (mm-with-unibyte-buffer
+ (mm-insert-part handle)
+ (cond ((looking-at mm-pkcs7-enveloped-magic)
+ 'enveloped)
+ ((looking-at mm-pkcs7-signed-magic)
+ 'signed)
+ (t
+ (error "Could not identify PKCS#7 type")))))
+
+(defun mm-view-pkcs7 (handle)
+ (case (mm-view-pkcs7-get-type handle)
+ (enveloped (mm-view-pkcs7-decrypt handle))
+ (otherwise (error "Unknown or unimplemented PKCS#7 type"))))
+
+(defun mm-view-pkcs7-decrypt (handle)
+ (insert-buffer (mm-handle-buffer handle))
+ (goto-char (point-min))
+ (insert "MIME-Version: 1.0\n")
+ (mm-insert-headers "application/pkcs7-mime" "base64" "smime.p7m")
+ (smime-decrypt-region
+ (point-min) (point-max)
+ (if (= (length smime-keys) 1)
+ (cadar smime-keys)
+ (smime-get-key-by-email
+ (completing-read "Decrypt this part with which key? "
+ smime-keys nil nil
+ (and (listp (car-safe smime-keys))
+ (caar smime-keys)))))))
+
(provide 'mm-view)
-;; mm-view.el ends here
+;;; mm-view.el ends here
;;; Code:
-(require 'smime)
(require 'mml2015)
+(require 'mml1991)
(require 'mml-smime)
(eval-when-compile (require 'cl))
(defvar mml-sign-alist
'(("smime" mml-smime-sign-buffer mml-smime-sign-query)
+ ("pgp" mml-pgp-sign-buffer list)
("pgpmime" mml-pgpmime-sign-buffer list))
"Alist of MIME signer functions.")
(defvar mml-encrypt-alist
'(("smime" mml-smime-encrypt-buffer mml-smime-encrypt-query)
+ ("pgp" mml-pgp-encrypt-buffer list)
("pgpmime" mml-pgpmime-encrypt-buffer list))
"Alist of MIME encryption functions.")
(or (mml-smime-encrypt cont)
(error "Encryption failed... inspect message logs for errors")))
+(defun mml-pgp-sign-buffer (cont)
+ (or (mml1991-sign cont)
+ (error "Signing failed... inspect message logs for errors")))
+
+(defun mml-pgp-encrypt-buffer (cont)
+ (or (mml1991-encrypt cont)
+ (error "Encryption failed... inspect message logs for errors")))
+
(defun mml-pgpmime-sign-buffer (cont)
(or (mml2015-sign cont)
(error "Signing failed... inspect message logs for errors")))
(when (string-match "[\"'\\~/*;() \t\n]" value)
(setq value (prin1-to-string value)))
(insert (format " %s=%s" key value))))))
- ((or (re-search-backward
+ ((or (re-search-backward
(concat "^" (regexp-quote mail-header-separator) "\n") nil t)
(re-search-forward
(concat "^" (regexp-quote mail-header-separator) "\n") nil t))
(goto-char (match-end 0))
(apply 'mml-insert-tag 'part (cons (if sign 'sign 'encrypt)
(cons method tags))))
- (t (error "The message is corrupted. No mail header separator."))))))
+ (t (error "The message is corrupted. No mail header separator"))))))
+
+(defun mml-secure-sign-pgp ()
+ "Add MML tags to PGP sign this MML part."
+ (interactive)
+ (mml-secure-part "pgp" 'sign))
(defun mml-secure-sign-pgpmime ()
"Add MML tags to PGP/MIME sign this MML part."
(interactive)
(mml-secure-part "smime" 'sign))
+(defun mml-secure-encrypt-pgp ()
+ "Add MML tags to PGP encrypt this MML part."
+ (interactive)
+ (mml-secure-part "pgp"))
+
(defun mml-secure-encrypt-pgpmime ()
"Add MML tags to PGP/MIME encrypt this MML part."
(interactive)
(when (null smime-keys)
(customize-variable 'smime-keys)
(error "No S/MIME keys configured, use customize to add your key"))
- (smime-sign-buffer (cdr (assq 'keyfile cont))))
+ (smime-sign-buffer (cdr (assq 'keyfile cont)))
+ (goto-char (point-max)))
(defun mml-smime-encrypt (cont)
(let (certnames certfiles tmp file tmpfiles)
t)
(while (setq tmp (pop tmpfiles))
(delete-file tmp))
- nil)))
+ nil))
+ (goto-char (point-max)))
(defun mml-smime-sign-query ()
;; query information (what certificate) from user when MML tag is
mm-security-handle 'gnus-info "Failed")
(mm-set-handle-multipart-parameter
mm-security-handle 'gnus-details
- (concat "OpenSSL failed to verify message:\n"
- "---------------------------------\n"
+ (concat "OpenSSL failed to verify message integrity:\n"
+ "-------------------------------------------\n"
openssl-output)))
;; verify mail addresses in mail against those in certificate
(when (and (smime-pkcs7-region (point-min) (point-max))
(mm-set-handle-multipart-parameter
mm-security-handle 'gnus-info "Ok (sender authenticated)")
(mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-info "Integrity OK (sender unknown)")))
+ mm-security-handle 'gnus-info "Ok (sender not trusted)")))
(mm-set-handle-multipart-parameter
mm-security-handle 'gnus-details
- (concat "Sender clamed to be: " (mm-handle-multipart-from ctl) "\n"
+ (concat "Sender claimed to be: " (mm-handle-multipart-from ctl) "\n"
(if addresses
(concat "Addresses in certificate: "
(mapconcat 'identity addresses ", "))
(autoload 'message-fetch-field "message")
(autoload 'message-posting-charset "message"))
+(defcustom mml-content-type-parameters
+ '(name access-type expiration size permission format)
+ "*A list of acceptable parameters in MML tag.
+These parameters are generated in Content-Type header if exists."
+ :type '(repeat (symbol :tag "Parameter"))
+ :group 'message)
+
+(defcustom mml-content-disposition-parameters
+ '(filename creation-date modification-date read-date)
+ "*A list of acceptable parameters in MML tag.
+These parameters are generated in Content-Disposition header if exists."
+ :type '(repeat (symbol :tag "Parameter"))
+ :group 'message)
+
+(defvar mml-tweak-type-alist nil
+ "A list of (TYPE . FUNCTION) for tweaking MML parts.
+TYPE is a string containing a regexp to match the MIME type. FUNCTION
+is a Lisp function which is called with the MML handle to tweak the
+part. This variable is used only when no TWEAK parameter exists in
+the MML handle.")
+
+(defvar mml-tweak-function-alist nil
+ "A list of (NAME . FUNCTION) for tweaking MML parts.
+NAME is a string containing the name of the TWEAK parameter in the MML
+handle. FUNCTION is a Lisp function which is called with the MML
+handle to tweak the part.")
+
(defvar mml-generate-multipart-alist nil
"*Alist of multipart generation functions.
Each entry has the form (NAME . FUNCTION), where
(setq raw (cdr (assq 'raw tag))
point (point)
contents (mml-read-part (eq 'mml (car tag)))
- charsets (if raw nil
- (mm-find-mime-charset-region point (point))))
+ charsets (cond
+ (raw nil)
+ ((assq 'charset tag)
+ (list
+ (intern (downcase (cdr (assq 'charset tag))))))
+ (t
+ (mm-find-mime-charset-region point (point)
+ mm-hack-charsets))))
(when (and (not raw) (memq nil charsets))
(if (or (memq 'unknown-encoding mml-confirmation-set)
- (prog1 (y-or-n-p
- "\
+ (message-options-get 'unknown-encoding)
+ (and (y-or-n-p "\
Message contains characters with unknown encoding. Really send?")
- (set (make-local-variable 'mml-confirmation-set)
- (push 'unknown-encoding mml-confirmation-set))))
+ (message-options-set 'unknown-encoding t)))
(if (setq use-ascii
(or (memq 'use-ascii mml-confirmation-set)
- (y-or-n-p "Use ASCII as charset?")))
+ (message-options-get 'use-ascii)
+ (and (y-or-n-p "Use ASCII as charset?")
+ (message-options-set 'use-ascii t))))
(setq charsets (delq nil charsets))
(setq warn nil))
(error "Edit your message to remove those characters")))
tag point (point) use-ascii)))
(when (and warn
(not (memq 'multipart mml-confirmation-set))
- (not
- (prog1 (y-or-n-p
- (format
- "\
+ (not (message-options-get 'multipart))
+ (not (and (y-or-n-p (format "\
A message part needs to be split into %d charset parts. Really send? "
- (length nstruct)))
- (set (make-local-variable 'mml-confirmation-set)
- (push 'multipart mml-confirmation-set)))))
+ (length nstruct)))
+ (message-options-set 'multipart t))))
(error "Edit your message to use only one charset"))
(setq struct (nconc nstruct struct)))))))
(unless (eobp)
"Return the buffer up till the next part, multipart or closing part or multipart.
If MML is non-nil, return the buffer up till the correspondent mml tag."
(let ((beg (point)) (count 1))
- ;; If the tag ended at the end of the line, we go to the next line.
+ ;; If the tag ended at the end of the line, we go to the next line.
(when (looking-at "[ \t]*\n")
(forward-line 1))
(if mml
(or mm-use-ultra-safe-encoding (assq 'sign cont))))
(save-restriction
(narrow-to-region (point) (point))
+ (mml-tweak-part cont)
(cond
((or (eq (car cont) 'part) (eq (car cont) 'mml))
(let ((raw (cdr (assq 'raw cont)))
(setq type (or (cdr (assq 'type cont)) "text/plain"))
(if (and (not raw)
(member (car (split-string type "/")) '("text" "message")))
- (with-temp-buffer
- (setq charset (mm-charset-to-coding-system
- (cdr (assq 'charset cont))))
- (when (eq charset 'ascii)
- (setq charset nil))
- (cond
- ((cdr (assq 'buffer cont))
- (insert-buffer-substring (cdr (assq 'buffer cont))))
- ((and (setq filename (cdr (assq 'filename cont)))
- (not (equal (cdr (assq 'nofile cont)) "yes")))
- (let ((coding-system-for-read charset))
- (mm-insert-file-contents filename)))
- ((eq 'mml (car cont))
- (insert (cdr (assq 'contents cont))))
- (t
- (save-restriction
- (narrow-to-region (point) (point))
- (insert (cdr (assq 'contents cont)))
- ;; Remove quotes from quoted tags.
- (goto-char (point-min))
- (while (re-search-forward
- "<#!+/?\\(part\\|multipart\\|external\\|mml\\)"
- nil t)
- (delete-region (+ (match-beginning 0) 2)
- (+ (match-beginning 0) 3))))))
- (cond
- ((eq (car cont) 'mml)
- (let ((mml-boundary (funcall mml-boundary-function
- (incf mml-multipart-number)))
- (mml-generate-default-type "text/plain"))
- (mml-to-mime))
- (let ((mm-7bit-chars (concat mm-7bit-chars "\x1b")))
- ;; ignore 0x1b, it is part of iso-2022-jp
- (setq encoding (mm-body-7-or-8))))
- ((string= (car (split-string type "/")) "message")
- (let ((mm-7bit-chars (concat mm-7bit-chars "\x1b")))
- ;; ignore 0x1b, it is part of iso-2022-jp
- (setq encoding (mm-body-7-or-8))))
- (t
- (setq charset (mm-encode-body charset))
- (setq encoding (mm-body-encoding
- charset (cdr (assq 'encoding cont))))))
- (setq coded (buffer-string)))
+ (progn
+ (with-temp-buffer
+ (setq charset (mm-charset-to-coding-system
+ (cdr (assq 'charset cont))))
+ (when (eq charset 'ascii)
+ (setq charset nil))
+ (cond
+ ((cdr (assq 'buffer cont))
+ (insert-buffer-substring (cdr (assq 'buffer cont))))
+ ((and (setq filename (cdr (assq 'filename cont)))
+ (not (equal (cdr (assq 'nofile cont)) "yes")))
+ (let ((coding-system-for-read charset))
+ (mm-insert-file-contents filename)))
+ ((eq 'mml (car cont))
+ (insert (cdr (assq 'contents cont))))
+ (t
+ (save-restriction
+ (narrow-to-region (point) (point))
+ (insert (cdr (assq 'contents cont)))
+ ;; Remove quotes from quoted tags.
+ (goto-char (point-min))
+ (while (re-search-forward
+ "<#!+/?\\(part\\|multipart\\|external\\|mml\\)"
+ nil t)
+ (delete-region (+ (match-beginning 0) 2)
+ (+ (match-beginning 0) 3))))))
+ (cond
+ ((eq (car cont) 'mml)
+ (let ((mml-boundary (funcall mml-boundary-function
+ (incf mml-multipart-number)))
+ (mml-generate-default-type "text/plain"))
+ (mml-to-mime))
+ (let ((mm-7bit-chars (concat mm-7bit-chars "\x1b")))
+ ;; ignore 0x1b, it is part of iso-2022-jp
+ (setq encoding (mm-body-7-or-8))))
+ ((string= (car (split-string type "/")) "message")
+ (let ((mm-7bit-chars (concat mm-7bit-chars "\x1b")))
+ ;; ignore 0x1b, it is part of iso-2022-jp
+ (setq encoding (mm-body-7-or-8))))
+ (t
+ (setq charset (mm-encode-body charset))
+ (setq encoding (mm-body-encoding
+ charset (cdr (assq 'encoding cont))))))
+ (setq coded (buffer-string)))
+ (mml-insert-mime-headers cont type charset encoding)
+ (insert "\n")
+ (insert coded))
(mm-with-unibyte-buffer
(cond
((cdr (assq 'buffer cont))
(t
(insert (cdr (assq 'contents cont)))))
(setq encoding (mm-encode-buffer type)
- coded (buffer-string))))
- (mml-insert-mime-headers cont type charset encoding)
- (insert "\n")
- (insert coded)))
+ coded (mm-string-as-multibyte (buffer-string))))
+ (mml-insert-mime-headers cont type charset encoding)
+ (insert "\n")
+ (mm-with-unibyte-current-buffer
+ (insert coded)))))
((eq (car cont) 'external)
(insert "Content-Type: message/external-body")
(let ((parameters (mml-parameter-string
(let (parameters disposition description)
(setq parameters
(mml-parameter-string
- cont '(name access-type expiration size permission)))
+ cont mml-content-type-parameters))
(when (or charset
parameters
(not (equal type mml-generate-default-type)))
"charset" (symbol-name charset))))
(when parameters
(mml-insert-parameter-string
- cont '(name access-type expiration size permission)))
+ cont mml-content-type-parameters))
(insert "\n"))
(setq parameters
(mml-parameter-string
- cont '(filename creation-date modification-date read-date)))
+ cont mml-content-disposition-parameters))
(when (or (setq disposition (cdr (assq 'disposition cont)))
parameters)
(insert "Content-Disposition: " (or disposition "inline"))
(when parameters
(mml-insert-parameter-string
- cont '(filename creation-date modification-date read-date)))
+ cont mml-content-disposition-parameters))
(insert "\n"))
(unless (eq encoding '7bit)
(insert (format "Content-Transfer-Encoding: %s\n" encoding)))
;; Remove them, they are confusing.
(message-remove-header "Content-Type")
(message-remove-header "MIME-Version")
+ (message-remove-header "Content-Disposition")
(message-remove-header "Content-Transfer-Encoding")))
(defun mml-to-mime ()
(map (make-sparse-keymap))
(main (make-sparse-keymap)))
(define-key sign "p" 'mml-secure-sign-pgpmime)
+ (define-key sign "o" 'mml-secure-sign-pgp)
(define-key sign "s" 'mml-secure-sign-smime)
(define-key encrypt "p" 'mml-secure-encrypt-pgpmime)
+ (define-key encrypt "o" 'mml-secure-encrypt-pgp)
(define-key encrypt "s" 'mml-secure-encrypt-smime)
(define-key map "f" 'mml-attach-file)
(define-key map "b" 'mml-attach-buffer)
main))
(easy-menu-define
- mml-menu mml-mode-map ""
- '("MML"
- ("Attach"
- ["File" mml-attach-file t]
- ["Buffer" mml-attach-buffer t]
- ["External" mml-attach-external t])
- ("Insert"
- ["Multipart" mml-insert-multipart t]
- ["Part" mml-insert-part t])
- ("Security"
- ("Sign"
- ["PGP/MIME" mml-secure-sign-pgpmime t]
- ["S/MIME" mml-secure-sign-smime t])
- ("Encrypt"
- ["PGP/MIME" mml-secure-encrypt-pgpmime t]
- ["S/MIME" mml-secure-encrypt-smime t]))
- ;;["Narrow" mml-narrow-to-part t]
- ["Quote" mml-quote-region t]
- ["Validate" mml-validate t]
- ["Preview" mml-preview t]))
+ mml-menu mml-mode-map ""
+ `("Attachments"
+ ["Attach File" mml-attach-file
+ ,@(if (featurep 'xemacs) '(t)
+ '(:help "Attach a file at point"))]
+ ["Attach Buffer" mml-attach-buffer t]
+ ["Attach External" mml-attach-external t]
+ ["Insert Part" mml-insert-part t]
+ ["Insert Multipart" mml-insert-multipart t]
+ ["PGP/MIME Sign" mml-secure-sign-pgpmime t]
+ ["PGP/MIME Encrypt" mml-secure-encrypt-pgpmime t]
+ ["PGP Sign" mml-secure-sign-pgp t]
+ ["PGP Encrypt" mml-secure-encrypt-pgp t]
+ ["S/MIME Sign" mml-secure-sign-smime t]
+ ["S/MIME Encrypt" mml-secure-encrypt-smime t]
+ ;;["Narrow" mml-narrow-to-part t]
+ ["Quote MML" mml-quote-region t]
+ ["Validate MML" mml-validate t]
+ ["Preview" mml-preview t]))
(defvar mml-mode nil
"Minor mode for editing MML.")
(defun mml-mode (&optional arg)
"Minor mode for editing MML.
+MML is the MIME Meta Language, a minor mode for composing MIME articles.
+See Info node `(emacs-mime)Composing'.
\\{mml-mode-map}"
(interactive "P")
(defun mml-minibuffer-read-file (prompt)
(let ((file (read-file-name prompt nil nil t)))
- ;; Prevent some common errors. This is inspired by similar code in
+ ;; Prevent some common errors. This is inspired by similar code in
;; VM.
(when (file-directory-p file)
(error "%s is a directory, cannot attach" file))
"Display current buffer with Gnus, in a new buffer.
If RAW, don't highlight the article."
(interactive "P")
- (let ((buf (current-buffer))
- (message-options message-options)
- (message-posting-charset (or (gnus-setup-posting-charset
- (save-restriction
- (message-narrow-to-headers-or-head)
- (message-fetch-field "Newsgroups")))
- message-posting-charset)))
+ (let* ((buf (current-buffer))
+ (message-options message-options)
+ (message-this-is-news (message-news-p))
+ (message-posting-charset (or (gnus-setup-posting-charset
+ (save-restriction
+ (message-narrow-to-headers-or-head)
+ (message-fetch-field "Newsgroups")))
+ message-posting-charset)))
(message-options-set-recipient)
(switch-to-buffer (generate-new-buffer
(concat (if raw "*Raw MIME preview of "
(if (re-search-forward
(concat "^" (regexp-quote mail-header-separator) "\n") nil t)
(replace-match "\n"))
- (mml-to-mime)
+ (let ((mail-header-separator "")) ;; mail-header-separator is removed.
+ (mml-to-mime))
(if raw
(when (fboundp 'set-buffer-multibyte)
(let ((s (buffer-string)))
(run-hooks 'gnus-article-decode-hook)
(let ((gnus-newsgroup-name "dummy"))
(gnus-article-prepare-display))))
- ;; Disable article-mode-map.
+ ;; Disable article-mode-map.
(use-local-map nil)
(setq buffer-read-only t)
(local-set-key "q" (lambda () (interactive) (kill-buffer nil)))
(interactive)
(mml-parse))
+(defun mml-tweak-part (cont)
+ "Tweak a MML part."
+ (let ((tweak (cdr (assq 'tweak cont)))
+ func)
+ (cond
+ (tweak
+ (setq func
+ (or (cdr (assoc tweak mml-tweak-function-alist))
+ (intern tweak))))
+ (mml-tweak-type-alist
+ (let ((alist mml-tweak-type-alist)
+ (type (or (cdr (assq 'type cont)) "text/plain")))
+ (while alist
+ (if (string-match (caar alist) type)
+ (setq func (cdar alist)
+ alist nil)
+ (setq alist (cdr alist)))))))
+ (if func
+ (funcall func cont)
+ cont)))
+
(provide 'mml)
;;; mml.el ends here
--- /dev/null
+;;; mml-gpg-old.el --- Old PGP message format (RFC 1991) support for MML
+;; Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+
+;; Author: Sascha Lüdecke <sascha@meta-x.de>,
+;; Simon Josefsson <simon@josefsson.org> (Mailcrypt interface, Gnus glue)
+;; Keywords PGP
+
+;; This file is (not yet) part of GNU Emacs.
+
+;; GNU Emacs 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 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; RCS: $Id: mml1991.el,v 1.1.1.1 2002-01-06 22:11:33 yamaoka Exp $
+
+;;; Code:
+
+(defvar mml1991-use mml2015-use
+ "The package used for PGP.")
+
+(defvar mml1991-function-alist
+ '((mailcrypt mml1991-mailcrypt-sign
+ mml1991-mailcrypt-encrypt)
+ (gpg mml1991-gpg-sign
+ mml1991-gpg-encrypt))
+ "Alist of PGP/MIME functions.")
+
+;;; mailcrypt wrapper
+
+(eval-and-compile
+ (autoload 'mc-sign-generic "mc-toplev"))
+
+(defvar mml1991-decrypt-function 'mailcrypt-decrypt)
+(defvar mml1991-verify-function 'mailcrypt-verify)
+
+(defun mml1991-mailcrypt-sign (cont)
+ (let ((text (current-buffer))
+ headers signature
+ (result-buffer (get-buffer-create "*GPG Result*")))
+ ;; Save MIME Content[^ ]+: headers from signing
+ (goto-char (point-min))
+ (while (looking-at "^Content[^ ]+:") (forward-line))
+ (if (> (point) (point-min))
+ (progn
+ (setq headers (buffer-substring (point-min) (point)))
+ (kill-region (point-min) (point))))
+ (goto-char (point-max))
+ (unless (bolp)
+ (insert "\n"))
+ (quoted-printable-decode-region (point-min) (point-max))
+ (with-temp-buffer
+ (setq signature (current-buffer))
+ (insert-buffer text)
+ (unless (mc-sign-generic (message-options-get 'message-sender)
+ nil nil nil nil)
+ (unless (> (point-max) (point-min))
+ (pop-to-buffer result-buffer)
+ (error "Sign error")))
+ (goto-char (point-min))
+ (while (re-search-forward "\r+$" nil t)
+ (replace-match "" t t))
+ (quoted-printable-encode-region (point-min) (point-max))
+ (set-buffer text)
+ (kill-region (point-min) (point-max))
+ (if headers (insert headers))
+ (insert "\n")
+ (insert-buffer signature)
+ (goto-char (point-max)))))
+
+(defun mml1991-mailcrypt-encrypt (cont)
+ (let ((text (current-buffer))
+ cipher
+ (result-buffer (get-buffer-create "*GPG Result*")))
+ ;; Strip MIME Content[^ ]: headers since it will be ASCII ARMOURED
+ (goto-char (point-min))
+ (while (looking-at "^Content[^ ]+:") (forward-line))
+ (if (> (point) (point-min))
+ (progn
+ (kill-region (point-min) (point))))
+ (mm-with-unibyte-current-buffer-mule4
+ (with-temp-buffer
+ (setq cipher (current-buffer))
+ (insert-buffer text)
+ (unless (mc-encrypt-generic
+ (or
+ (message-options-get 'message-recipients)
+ (message-options-set 'message-recipients
+ (read-string "Recipients: ")))
+ nil
+ (point-min) (point-max)
+ (message-options-get 'message-sender)
+ 'sign)
+ (unless (> (point-max) (point-min))
+ (pop-to-buffer result-buffer)
+ (error "Encrypt error")))
+ (goto-char (point-min))
+ (while (re-search-forward "\r+$" nil t)
+ (replace-match "" t t))
+ (set-buffer text)
+ (kill-region (point-min) (point-max))
+ ;;(insert "Content-Type: application/pgp-encrypted\n\n")
+ ;;(insert "Version: 1\n\n")
+ (insert "\n")
+ (insert-buffer cipher)
+ (goto-char (point-max))))))
+
+;;; gpg wrapper
+
+(eval-and-compile
+ (autoload 'gpg-sign-cleartext "gpg"))
+
+(defun mml1991-gpg-sign (cont)
+ (let ((text (current-buffer))
+ headers signature
+ (result-buffer (get-buffer-create "*GPG Result*")))
+ ;; Save MIME Content[^ ]+: headers from signing
+ (goto-char (point-min))
+ (while (looking-at "^Content[^ ]+:") (forward-line))
+ (if (> (point) (point-min))
+ (progn
+ (setq headers (buffer-substring (point-min) (point)))
+ (kill-region (point-min) (point))))
+ (goto-char (point-max))
+ (unless (bolp)
+ (insert "\n"))
+ (quoted-printable-decode-region (point-min) (point-max))
+ (with-temp-buffer
+ (unless (gpg-sign-cleartext text (setq signature (current-buffer))
+ result-buffer
+ nil
+ (message-options-get 'message-sender))
+ (unless (> (point-max) (point-min))
+ (pop-to-buffer result-buffer)
+ (error "Sign error")))
+ (goto-char (point-min))
+ (while (re-search-forward "\r+$" nil t)
+ (replace-match "" t t))
+ (quoted-printable-encode-region (point-min) (point-max))
+ (set-buffer text)
+ (kill-region (point-min) (point-max))
+ (if headers (insert headers))
+ (insert "\n")
+ (insert-buffer signature)
+ (goto-char (point-max)))))
+
+(defun mml1991-gpg-encrypt (cont)
+ (let ((text (current-buffer))
+ cipher
+ (result-buffer (get-buffer-create "*GPG Result*")))
+ ;; Strip MIME Content[^ ]: headers since it will be ASCII ARMOURED
+ (goto-char (point-min))
+ (while (looking-at "^Content[^ ]+:") (forward-line))
+ (if (> (point) (point-min))
+ (progn
+ (kill-region (point-min) (point))))
+ (mm-with-unibyte-current-buffer-mule4
+ (with-temp-buffer
+ (unless (gpg-sign-encrypt
+ text (setq cipher (current-buffer))
+ result-buffer
+ (split-string
+ (or
+ (message-options-get 'message-recipients)
+ (message-options-set 'message-recipients
+ (read-string "Recipients: ")))
+ "[ \f\t\n\r\v,]+")
+ nil
+ (message-options-get 'message-sender)
+ t t) ; armor & textmode
+ (unless (> (point-max) (point-min))
+ (pop-to-buffer result-buffer)
+ (error "Encrypt error")))
+ (goto-char (point-min))
+ (while (re-search-forward "\r+$" nil t)
+ (replace-match "" t t))
+ (set-buffer text)
+ (kill-region (point-min) (point-max))
+ ;;(insert "Content-Type: application/pgp-encrypted\n\n")
+ ;;(insert "Version: 1\n\n")
+ (insert "\n")
+ (insert-buffer cipher)
+ (goto-char (point-max))))))
+
+;;;###autoload
+(defun mml1991-encrypt (cont)
+ (let ((func (nth 2 (assq mml1991-use mml1991-function-alist))))
+ (if func
+ (funcall func cont)
+ (error "Cannot find encrypt function"))))
+
+;;;###autoload
+(defun mml1991-sign (cont)
+ (let ((func (nth 1 (assq mml1991-use mml1991-function-alist))))
+ (if func
+ (funcall func cont)
+ (error "Cannot find sign function"))))
+
+(provide 'mml1991)
+
+;; Local Variables:
+;; coding: iso-8859-1
+;; End:
+
+;;; mml1991.el ends here
;;; Commentary:
+;; RFC 2015 is updated by RFC 3156, this file should be compatible
+;; with both.
+
;;; Code:
(eval-when-compile (require 'cl))
(defvar mml2015-result-buffer nil)
+(defvar mml2015-trust-boundaries-alist
+ '((trust-undefined . nil)
+ (trust-none . nil)
+ (trust-marginal . t)
+ (trust-full . t)
+ (trust-ultimate . t))
+ "Trust boundaries for a signer's GnuPG key.
+This alist contains pairs of the form (trust-symbol . boolean), with
+symbols that are contained in `gpg-unabbrev-trust-alist'. The boolean
+specifies whether the given trust value is good enough to be trusted
+by you.")
+
;;; mailcrypt wrapper
(eval-and-compile
(defvar mml2015-decrypt-function 'mailcrypt-decrypt)
(defvar mml2015-verify-function 'mailcrypt-verify)
+(defun mml2015-format-error (err)
+ (if (stringp (cadr err))
+ (cadr err)
+ (format "%S" (cdr err))))
+
(defun mml2015-mailcrypt-decrypt (handle ctl)
(catch 'error
(let (child handles result)
(funcall mml2015-decrypt-function)
(error
(mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-details (cadr err))
+ mm-security-handle 'gnus-details (mml2015-format-error err))
nil)
(quit
(mm-set-handle-multipart-parameter
(funcall mml2015-decrypt-function)
(error
(mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-details (cadr err))
+ mm-security-handle 'gnus-details (mml2015-format-error err))
nil)
(quit
(mm-set-handle-multipart-parameter
(defun mml2015-fix-micalg (alg)
(and alg
- (upcase (if (string-match "^pgp-" alg)
+ ;; Mutt/1.2.5i has seen sending micalg=php-sha1
+ (upcase (if (string-match "^p[gh]p-" alg)
(substring alg (match-end 0))
alg))))
(replace-match "-----BEGIN PGP SIGNATURE-----" t t))
(if (re-search-forward "^-----END PGP [^-]+-----\r?$" nil t)
(replace-match "-----END PGP SIGNATURE-----" t t)))
- (unless (condition-case err
- (funcall mml2015-verify-function)
- (error
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-details (cadr err))
- nil)
- (quit
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-details "Quit.")
- nil))
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-info "Failed")
- (throw 'error handle)))
+ (let ((mc-gpg-debug-buffer (get-buffer-create " *gnus gpg debug*")))
+ (unless (condition-case err
+ (prog1
+ (funcall mml2015-verify-function)
+ (if (get-buffer " *mailcrypt stderr temp")
+ (mm-set-handle-multipart-parameter
+ mm-security-handle 'gnus-details
+ (with-current-buffer " *mailcrypt stderr temp"
+ (buffer-string))))
+ (if (get-buffer " *mailcrypt stdout temp")
+ (kill-buffer " *mailcrypt stdout temp"))
+ (if (get-buffer " *mailcrypt stderr temp")
+ (kill-buffer " *mailcrypt stderr temp"))
+ (if (get-buffer " *mailcrypt status temp")
+ (kill-buffer " *mailcrypt status temp"))
+ (if (get-buffer mc-gpg-debug-buffer)
+ (kill-buffer mc-gpg-debug-buffer)))
+ (error
+ (mm-set-handle-multipart-parameter
+ mm-security-handle 'gnus-details (mml2015-format-error err))
+ nil)
+ (quit
+ (mm-set-handle-multipart-parameter
+ mm-security-handle 'gnus-details "Quit.")
+ nil))
+ (mm-set-handle-multipart-parameter
+ mm-security-handle 'gnus-info "Failed")
+ (throw 'error handle))))
(mm-set-handle-multipart-parameter
mm-security-handle 'gnus-info "OK")
handle)))
(defun mml2015-mailcrypt-clear-verify ()
- (if (condition-case err
- (funcall mml2015-verify-function)
- (error
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-details (cadr err))
- nil)
- (quit
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-details "Quit.")
- nil))
+ (let ((mc-gpg-debug-buffer (get-buffer-create " *gnus gpg debug*")))
+ (if (condition-case err
+ (prog1
+ (funcall mml2015-verify-function)
+ (if (get-buffer " *mailcrypt stderr temp")
+ (mm-set-handle-multipart-parameter
+ mm-security-handle 'gnus-details
+ (with-current-buffer " *mailcrypt stderr temp"
+ (buffer-string))))
+ (if (get-buffer " *mailcrypt stdout temp")
+ (kill-buffer " *mailcrypt stdout temp"))
+ (if (get-buffer " *mailcrypt stderr temp")
+ (kill-buffer " *mailcrypt stderr temp"))
+ (if (get-buffer " *mailcrypt status temp")
+ (kill-buffer " *mailcrypt status temp"))
+ (if (get-buffer mc-gpg-debug-buffer)
+ (kill-buffer mc-gpg-debug-buffer)))
+ (error
+ (mm-set-handle-multipart-parameter
+ mm-security-handle 'gnus-details (mml2015-format-error err))
+ nil)
+ (quit
+ (mm-set-handle-multipart-parameter
+ mm-security-handle 'gnus-details "Quit.")
+ nil))
+ (mm-set-handle-multipart-parameter
+ mm-security-handle 'gnus-info "OK")
(mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-info "OK")
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-info "Failed")))
+ mm-security-handle 'gnus-info "Failed"))))
(defun mml2015-mailcrypt-sign (cont)
(mc-sign-generic (message-options-get 'message-sender)
hash point)
(goto-char (point-min))
(unless (re-search-forward "^-----BEGIN PGP SIGNED MESSAGE-----\r?$" nil t)
- (error "Cannot find signed begin line." ))
+ (error "Cannot find signed begin line"))
(goto-char (match-beginning 0))
(forward-line 1)
(unless (looking-at "Hash:[ \t]*\\([a-zA-Z0-9]+\\)")
- (error "Cannot not find PGP hash." ))
+ (error "Cannot not find PGP hash"))
(setq hash (match-string 1))
(unless (re-search-forward "^$" nil t)
- (error "Cannot not find PGP message." ))
+ (error "Cannot not find PGP message"))
(forward-line 1)
(delete-region (point-min) (point))
(insert (format "Content-Type: multipart/signed; boundary=\"%s\";\n"
(setq point (point))
(goto-char (point-max))
(unless (re-search-backward "^-----END PGP SIGNATURE-----\r?$" nil t)
- (error "Cannot find signature part." ))
+ (error "Cannot find signature part"))
(replace-match "-----END PGP MESSAGE-----" t t)
(goto-char (match-beginning 0))
(unless (re-search-backward "^-----BEGIN PGP SIGNATURE-----\r?$"
nil t)
- (error "Cannot find signature part." ))
+ (error "Cannot find signature part"))
(replace-match "-----BEGIN PGP MESSAGE-----" t t)
(goto-char (match-beginning 0))
(save-restriction
(message-options-get 'message-sender))))
(goto-char (point-min))
(unless (looking-at "-----BEGIN PGP MESSAGE-----")
- (error "Fail to encrypt the message."))
+ (error "Fail to encrypt the message"))
(let ((boundary
(funcall mml-boundary-function (incf mml-multipart-number))))
(insert (format "Content-Type: multipart/encrypted; boundary=\"%s\";\n"
(buffer-string)))
(set-buffer cipher)
(erase-buffer)
- (insert-buffer plain)))
+ (insert-buffer plain)
+ (goto-char (point-min))
+ (while (search-forward "\r\n" nil t)
+ (replace-match "\n" t t))))
'(t)
;; Some wrong with the return value, check plain text buffer.
(if (> (point-max) (point-min))
(mm-set-handle-multipart-parameter
mm-security-handle 'gnus-info "Failed"))))
-(defun mml2015-gpg-extract-from ()
+(defun mml2015-gpg-pretty-print-fpr (fingerprint)
+ (let* ((result "")
+ (fpr-length (string-width fingerprint))
+ (n-slice 0)
+ slice)
+ (setq fingerprint (string-to-list fingerprint))
+ (while fingerprint
+ (setq fpr-length (- fpr-length 4))
+ (setq slice (butlast fingerprint fpr-length))
+ (setq fingerprint (nthcdr 4 fingerprint))
+ (setq n-slice (1+ n-slice))
+ (setq result
+ (concat
+ result
+ (case n-slice
+ (1 slice)
+ (otherwise (concat " " slice))))))
+ result))
+
+(defun mml2015-gpg-extract-signature-details ()
(goto-char (point-min))
- (if (re-search-forward "^gpg: Good signature from \"\\(.*\\)\"$" nil t)
- (match-string 1)
- "From unknown user"))
+ (if (boundp 'gpg-unabbrev-trust-alist)
+ (let* ((signer (and (re-search-forward
+ "^\\[GNUPG:\\] GOODSIG [0-9A-Za-z]* \\(.*\\)$"
+ nil t)
+ (match-string 1)))
+ (fprint (and (re-search-forward
+ "^\\[GNUPG:\\] VALIDSIG \\([0-9a-zA-Z]*\\) "
+ nil t)
+ (match-string 1)))
+ (trust (and (re-search-forward "^\\[GNUPG:\\] \\(TRUST_.*\\)$" nil t)
+ (match-string 1)))
+ (trust-good-enough-p
+ (cdr (assoc (cdr (assoc trust gpg-unabbrev-trust-alist))
+ mml2015-trust-boundaries-alist))))
+ (if (and signer trust fprint)
+ (concat signer
+ (unless trust-good-enough-p
+ (concat "\nUntrusted, Fingerprint: "
+ (mml2015-gpg-pretty-print-fpr fprint))))
+ "From unknown user"))
+ (if (re-search-forward "^gpg: Good signature from \"\\(.*\\)\"$" nil t)
+ (match-string 1)
+ "From unknown user")))
(defun mml2015-gpg-verify (handle ctl)
(catch 'error
- (let (part message signature)
+ (let (part message signature info-is-set-p)
(unless (setq part (mm-find-raw-part-by-type
ctl (or (mm-handle-multipart-ctl-parameter
ctl 'protocol)
(with-temp-buffer
(setq message (current-buffer))
(insert part)
+ ;; Convert <LF> to <CR><LF> in verify mode. Sign and
+ ;; clearsign use --textmode. The conversion is not necessary.
+ ;; In clearverify, the conversion is not necessary either.
+ (goto-char (point-min))
+ (end-of-line)
+ (while (not (eobp))
+ (unless (eq (char-before) ?\r)
+ (insert "\r"))
+ (forward-line)
+ (end-of-line))
(with-temp-buffer
(setq signature (current-buffer))
(unless (setq part (mm-find-part-by-type
(buffer-string))))
(error
(mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-details (cadr err))
+ mm-security-handle 'gnus-details (mml2015-format-error err))
+ (mm-set-handle-multipart-parameter
+ mm-security-handle 'gnus-info "Error.")
+ (setq info-is-set-p t)
nil)
(quit
(mm-set-handle-multipart-parameter
mm-security-handle 'gnus-details "Quit.")
+ (mm-set-handle-multipart-parameter
+ mm-security-handle 'gnus-info "Quit.")
+ (setq info-is-set-p t)
nil))
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-info "Failed")
+ (unless info-is-set-p
+ (mm-set-handle-multipart-parameter
+ mm-security-handle 'gnus-info "Failed"))
(throw 'error handle)))
(mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-info
- (with-current-buffer mml2015-result-buffer
- (mml2015-gpg-extract-from))))
+ mm-security-handle 'gnus-info
+ (with-current-buffer mml2015-result-buffer
+ (mml2015-gpg-extract-signature-details))))
handle)))
(defun mml2015-gpg-clear-verify ()
(buffer-string))))
(error
(mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-details (cadr err))
+ mm-security-handle 'gnus-details (mml2015-format-error err))
nil)
(quit
(mm-set-handle-multipart-parameter
mm-security-handle 'gnus-details "Quit.")
nil))
(mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-info
- (with-current-buffer mml2015-result-buffer
- (mml2015-gpg-extract-from)))
+ mm-security-handle 'gnus-info
+ (with-current-buffer mml2015-result-buffer
+ (mml2015-gpg-extract-signature-details)))
(mm-set-handle-multipart-parameter
mm-security-handle 'gnus-info "Failed")))
t t) ; armor & textmode
(unless (> (point-max) (point-min))
(pop-to-buffer mml2015-result-buffer)
- (error "Sign error.")))
+ (error "Sign error")))
(goto-char (point-min))
(while (re-search-forward "\r+$" nil t)
(replace-match "" t t))
t t) ; armor & textmode
(unless (> (point-max) (point-min))
(pop-to-buffer mml2015-result-buffer)
- (error "Encrypt error.")))
+ (error "Encrypt error")))
(goto-char (point-min))
(while (re-search-forward "\r+$" nil t)
(replace-match "" t t))
(let ((func (nth 2 (assq mml2015-use mml2015-function-alist))))
(if func
(funcall func cont)
- (error "Cannot find encrypt function."))))
+ (error "Cannot find encrypt function"))))
;;;###autoload
(defun mml2015-sign (cont)
(let ((func (nth 1 (assq mml2015-use mml2015-function-alist))))
(if func
(funcall func cont)
- (error "Cannot find sign function."))))
+ (error "Cannot find sign function"))))
;;;###autoload
(defun mml2015-self-encrypt ()
;;; nnagent.el --- offline backend for Gnus
-;; Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+
+;; Copyright (C) 1997, 1998, 1999, 2000, 2001
+;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;; Keywords: news, mail
(nnagent-active-file ,(gnus-agent-lib-file "active"))
(nnagent-newsgroups-file ,(gnus-agent-lib-file "newsgroups"))
(nnagent-get-new-mail nil)))
- (nnoo-change-server 'nnagent
+ (nnoo-change-server 'nnagent
(nnagent-server server)
defs)
(let ((dir (gnus-agent-directory))
(deffoo nnagent-request-set-mark (group action server)
(with-temp-buffer
(insert (format "(%s-request-set-mark \"%s\" '%s \"%s\")\n"
- (nth 0 gnus-command-method) group action
- (or server (nth 1 gnus-command-method))))
+ (nth 0 gnus-command-method) group action
+ (or server (nth 1 gnus-command-method))))
(append-to-file (point-min) (point-max) (gnus-agent-lib-file "flags")))
nil)
(deffoo nnagent-request-group (group &optional server dont-check)
(nnoo-parent-function 'nnagent 'nnml-request-group
- (list group (nnagent-server server) dont-check)))
+ (list group (nnagent-server server) dont-check)))
(deffoo nnagent-close-group (group &optional server)
(nnoo-parent-function 'nnagent 'nnml-close-group
- (list group (nnagent-server server))))
+ (list group (nnagent-server server))))
(deffoo nnagent-request-accept-article (group &optional server last)
(nnoo-parent-function 'nnagent 'nnml-request-accept-article
- (list group (nnagent-server server) last)))
+ (list group (nnagent-server server) last)))
(deffoo nnagent-request-article (id &optional group server buffer)
(nnoo-parent-function 'nnagent 'nnml-request-article
- (list id group (nnagent-server server) buffer)))
+ (list id group (nnagent-server server) buffer)))
(deffoo nnagent-request-create-group (group &optional server args)
(nnoo-parent-function 'nnagent 'nnml-request-create-group
- (list group (nnagent-server server) args)))
+ (list group (nnagent-server server) args)))
(deffoo nnagent-request-delete-group (group &optional force server)
(nnoo-parent-function 'nnagent 'nnml-request-delete-group
- (list group force (nnagent-server server))))
+ (list group force (nnagent-server server))))
(deffoo nnagent-request-expire-articles (articles group &optional server force)
(nnoo-parent-function 'nnagent 'nnml-request-expire-articles
- (list articles group (nnagent-server server) force)))
+ (list articles group (nnagent-server server) force)))
(deffoo nnagent-request-list (&optional server)
- (nnoo-parent-function 'nnagent 'nnml-request-list
- (list (nnagent-server server))))
+ (nnoo-parent-function 'nnagent 'nnml-request-list
+ (list (nnagent-server server))))
(deffoo nnagent-request-list-newsgroups (&optional server)
- (nnoo-parent-function 'nnagent 'nnml-request-list-newsgroups
- (list (nnagent-server server))))
+ (nnoo-parent-function 'nnagent 'nnml-request-list-newsgroups
+ (list (nnagent-server server))))
-(deffoo nnagent-request-move-article
+(deffoo nnagent-request-move-article
(article group server accept-form &optional last)
- (nnoo-parent-function 'nnagent 'nnml-request-move-article
- (list article group (nnagent-server server)
- accept-form last)))
+ (nnoo-parent-function 'nnagent 'nnml-request-move-article
+ (list article group (nnagent-server server)
+ accept-form last)))
(deffoo nnagent-request-rename-group (group new-name &optional server)
- (nnoo-parent-function 'nnagent 'nnml-request-rename-group
- (list group new-name (nnagent-server server))))
+ (nnoo-parent-function 'nnagent 'nnml-request-rename-group
+ (list group new-name (nnagent-server server))))
(deffoo nnagent-request-scan (&optional group server)
- (nnoo-parent-function 'nnagent 'nnml-request-scan
- (list group (nnagent-server server))))
+ (nnoo-parent-function 'nnagent 'nnml-request-scan
+ (list group (nnagent-server server))))
(deffoo nnagent-retrieve-headers (sequence &optional group server fetch-old)
- (nnoo-parent-function 'nnagent 'nnml-retrieve-headers
- (list sequence group (nnagent-server server) fetch-old)))
+ (nnoo-parent-function 'nnagent 'nnml-retrieve-headers
+ (list sequence group (nnagent-server server) fetch-old)))
(deffoo nnagent-set-status (article name value &optional group server)
- (nnoo-parent-function 'nnagent 'nnml-set-status
- (list article name value group (nnagent-server server))))
+ (nnoo-parent-function 'nnagent 'nnml-set-status
+ (list article name value group (nnagent-server server))))
(deffoo nnagent-server-opened (&optional server)
(nnoo-parent-function 'nnagent 'nnml-server-opened
;;; nnbabyl.el --- rmail mbox access for Gnus
-;; Copyright (C) 1995, 1996, 1997, 1998, 1099, 2000
+;; Copyright (C) 1995, 1996, 1997, 1998, 1099, 2000, 2001
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
(defvoo nnbabyl-get-new-mail t
"If non-nil, nnbabyl will check the incoming mail file and split the mail.")
+
(defvoo nnbabyl-prepare-save-mail-hook nil
"Hook run narrowed to an article before saving.")
(progn
(unless (eq nnmail-expiry-target 'delete)
(with-temp-buffer
- (nnbabyl-request-article (car articles)
- newsgroup server
+ (nnbabyl-request-article (car articles)
+ newsgroup server
(current-buffer))
(let ((nnml-current-directory nil))
(nnmail-expiry-target-group
- nnmail-expiry-target newsgroup))))
+ nnmail-expiry-target newsgroup)))
+ (nnbabyl-possibly-change-newsgroup newsgroup server))
(nnheader-message 5 "Deleting article %d in %s..."
(car articles) newsgroup)
(nnbabyl-delete-mail))
(nntp-send-command "^\\([23]\\|^423\\).*\n" "X-DATE" art)
(setq msg (nndb-status-message))
(if (string-match "^423" msg)
- ()
+ ()
(or (string-match "'\\(.+\\)'" msg)
(error "Not a valid response for X-DATE command: %s"
msg))
(set-buffer nntp-server-buffer)
(goto-char (point-min))
(if (looking-at "^[34]")
- ;; x-expire returned error--presume no articles were expirable)
+ ;; x-expire returned error--presume no articles were expirable)
(setq list nil)
;; otherwise, pull all of the following numbers into the list
(re-search-forward "follows\r?\n?" nil t)
(while (re-search-forward "^[0-9]+$" nil t)
- (push (string-to-int (match-string 0)) list)))
+ (push (string-to-int (match-string 0)) list)))
list))
(defun nndb-request-expire-articles-remote
;; first calculate the wait period in days
(setq days (or (and nnmail-expiry-wait-function
(funcall nnmail-expiry-wait-function group))
- nnmail-expiry-wait))
+ nnmail-expiry-wait))
;; now handle the special cases
(cond (force
- (setq days 0))
+ (setq days 0))
((eq days 'never)
;; This isn't an expirable group.
- (setq days -1))
+ (setq days -1))
((eq days 'immediate)
- (setq days 0)))
+ (setq days 0)))
;; build article string
(cons new-group article))
;; else move normally
(let ((artbuf (get-buffer-create " *nndb move*")))
- (and
- (nndb-request-article article group server artbuf)
- (save-excursion
- (set-buffer artbuf)
- (insert-buffer-substring nntp-server-buffer)
- (setq result (eval accept-form))
- (kill-buffer (current-buffer))
- result)
- (nndb-request-expire-articles (list article)
- group
- server
- t))
- result)
+ (and
+ (nndb-request-article article group server artbuf)
+ (save-excursion
+ (set-buffer artbuf)
+ (insert-buffer-substring nntp-server-buffer)
+ (setq result (eval accept-form))
+ (kill-buffer (current-buffer))
+ result)
+ (nndb-request-expire-articles (list article)
+ group
+ server
+ t))
+ result)
)))
(deffoo nndb-request-accept-article (group server &optional last)
(nntp-send-buffer "^[23.*\n")
(list (int-to-string article))))
-; nndb-request-delete-group does not exist
-; todo -- maybe later
+ ; nndb-request-delete-group does not exist
+ ; todo -- maybe later
-; nndb-request-rename-group does not exist
-; todo -- maybe later
+ ; nndb-request-rename-group does not exist
+ ; todo -- maybe later
;; -- standard compatability functions
(nntp))
(provide 'nndb)
+
+;;; nndb.el ends here
--- /dev/null
+;;; nndiary.el --- A diary backend for Gnus
+
+;; Copyright (C) 1999, 2000, 2001
+;; Free Software Foundation, Inc.
+
+;; Author: Didier Verna <didier@xemacs.org>
+;; Maintainer: Didier Verna <didier@xemacs.org>
+;; Created: Fri Jul 16 18:55:42 1999
+;; Keywords: calendar mail news
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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 2 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+;;; Commentary:
+
+;; Contents management by FCM version 0.1.
+
+;; Description:
+;; ===========
+
+;; This package implements NNDiary, a diary backend for Gnus. NNDiary is a
+;; mail backend, pretty similar to nnml in its functionnning (it has all the
+;; features of nnml, actually), but in which messages are treated as event
+;; reminders.
+
+;; Here is a typical scenario:
+;; - You've got a date with Andy Mc Dowell or Bruce Willis (select according
+;; to your sexual preference) in one month. You don't want to forget it.
+;; - Send a (special) diary message to yourself (see below).
+;; - Forget all about it and keep on getting and reading new mail, as usual.
+;; - From time to time, as you type `g' in the group buffer and as the date
+;; is getting closer, the message will pop up again, just like if it were
+;; new and unread.
+;; - Read your "new" messages, this one included, and start dreaming of the
+;; night you're gonna have.
+;; - Once the date is over (you actually fell asleep just after dinner), the
+;; message will be automatically deleted if it is marked as expirable.
+
+;; Some more notes on the diary backend:
+;; - NNDiary is a *real* mail backend. You *really* send real diary
+;; messsages. This means for instance that you can give appointements to
+;; anybody (provided they use Gnus and NNDiary) by sending the diary message
+;; to them as well.
+;; - However, since NNDiary also has a 'request-post method, you can also
+;; `C-u a' instead of `C-u m' on a diary group and the message won't actually
+;; be sent; just stored in the group.
+;; - The events you want to remember need not be punctual. You can set up
+;; reminders for regular dates (like once each week, each monday at 13:30
+;; and so on). Diary messages of this kind will never be deleted (unless
+;; you do it explicitely). But that, you guessed.
+
+
+;; Usage:
+;; =====
+
+;; 1/ NNDiary has two modes of operation: traditional (the default) and
+;; autonomous.
+;; a/ In traditional mode, NNDiary does not get new mail by itself. You
+;; have to move mails from your primary mail backend to nndiary
+;; groups.
+;; b/ In autonomous mode, NNDiary retrieves its own mail and handles it
+;; independantly of your primary mail backend. To use NNDiary in
+;; autonomous mode, you have several things to do:
+;; i/ Put (setq nndiary-get-new-mail t) in your gnusrc file.
+;; ii/ Diary messages contain several `X-Diary-*' special headers.
+;; You *must* arrange that these messages be split in a private
+;; folder *before* Gnus treat them. You need this because Gnus
+;; is not able yet to manage multiple backends for mail
+;; retrieval. Getting them from a separate source will
+;; compensate this misfeature to some extent, as we will see.
+;; As an example, here's my procmailrc entry to store diary files
+;; in ~/.nndiary (the default nndiary mail source file):
+;;
+;; :0 HD :
+;; * ^X-Diary
+;; .nndiary
+;; iii/ Customize the variables `nndiary-mail-sources' and
+;; `nndiary-split-methods'. These are replacements for the usual
+;; mail sources and split methods which, and will be used in
+;; autonomous mode. `nndiary-mail-sources' defaults to
+;; '(file :path "~/.nndiary").
+;; 2/ Install nndiary somewhere Emacs / Gnus can find it. Normally, you
+;; *don't* have to '(require 'nndiary) anywhere. Gnus will do so when
+;; appropriate as long as nndiary is somewhere in the load path.
+;; 3/ Now, customize the rest of nndiary. In particular, you should
+;; customize `nndiary-reminders', the list of times when you want to be
+;; reminded of your appointements (e.g. 3 weeks before, then 2 days
+;; before, then 1 hour before and that's it).
+;; 4/ You *must* use the group timestamp feature of Gnus. This adds a
+;; timestamp to each groups' parameters (please refer to the Gnus
+;; documentation ("Group Timestamp" info node) to see how it's done.
+;; 5/ Once you have done this, you may add a permanent nndiary virtual server
+;; (something like '(nndiary "")) to your `gnus-secondary-select-methods'.
+;; Yes, this server will be able to retrieve mails and split them when you
+;; type `g' in the group buffer, just as if it were your only mail backend.
+;; This is the benefit of using a private folder.
+;; 6/ Hopefully, almost everything (see the TODO section below) will work as
+;; expected when you restart Gnus: in the group buffer, `g' and `M-g' will
+;; also get your new diary mails, `F' will find your new diary groups etc.
+
+
+;; How to send diary messages:
+;; ==========================
+
+;; There are 7 special headers in diary messages. These headers are of the
+;; form `X-Diary-<something>', the <something> being one of `Minute', `Hour',
+;; `Dom', `Month', `Year', `Time-Zone' and `Dow'. `Dom' means "Day of Month",
+;; and `dow' means "Day of Week". These headers actually behave like crontab
+;; specifications and define the event date(s).
+
+;; For all headers but the `Time-Zone' one, a header value is either a
+;; star (meaning all possible values), or a list of fields (separated by a
+;; comma). A field is either an integer, or a range. A range is two integers
+;; separated by a dash. Possible integer values are 0-59 for `Minute', 0-23
+;; for `Hour', 1-31 for `Dom', `1-12' for Month, above 1971 for `Year' and 0-6
+;; for `Dow' (0 = sunday). As a special case, a star in either `Dom' or `Dow'
+;; doesn't mean "all possible values", but "use only the other field". Note
+;; that if both are star'ed, the use of either one gives the same result :-),
+
+;; The `Time-Zone' header is special in that it can have only one value (you
+;; bet ;-).
+;; A star doesn't mean "all possible values" (because it has no sense), but
+;; "the current local time zone".
+
+;; As an example, here's how you would say "Each Monday and each 1st of month,
+;; at 12:00, 20:00, 21:00, 22:00, 23:00 and 24:00, from 1999 to 2010" (I let
+;; you find what to do then):
+;;
+;; X-Diary-Minute: 0
+;; X-Diary-Hour: 12, 20-24
+;; X-Diary-Dom: 1
+;; X-Diary-Month: *
+;; X-Diary-Year: 1999-2010
+;; X-Diary-Dow: 1
+;; X-Diary-Time-Zone: *
+;;
+;;
+;; Sending a diary message is not different from sending any other kind of
+;; mail, except that such messages are identified by the presence of these
+;; special headers.
+
+
+
+;; Bugs / Todo:
+;; ===========
+
+;; * Respooling doesn't work because contrary to the request-scan function,
+;; Gnus won't allow me to override the split methods when calling the
+;; respooling backend functions.
+;; * There's a bug in the time zone mechanism with variable TZ locations.
+;; * We could allow a keyword like `ask' in X-Diary-* headers, that would mean
+;; "ask for value upon reception of the message".
+;; * We could add an optional header X-Diary-Reminders to specify a special
+;; reminders value for this message. Suggested by Jody Klymak.
+;; * We should check messages validity in other circumstances than just
+;; moving an article from sonwhere else (request-accept). For instance, when
+;; editing / saving and so on.
+
+
+;; Remarks:
+;; =======
+
+;; * nnoo.
+;; NNDiary is very similar to nnml. This makes the idea of using nnoo (to
+;; derive nndiary from nnml) natural. However, my experience with nnoo is
+;; that for reasonably complex backends like this one, noo is a burden
+;; rather than an help. It's tricky to use, not everything can be
+;; inherited, what can be inherited and when is not very clear, and you've
+;; got to be very careful because a little mistake can fuck up your your
+;; other backends, especially because their variables will be use instead of
+;; your real ones. Finally, I found it easier to just clone the needed
+;; parts of nnml, and tracking nnml updates is not a big deal.
+
+;; IMHO, nnoo is actually badly designed. A much simpler, and yet more
+;; powerful one would be to make *real* functions and variables for a new
+;; backend based on another. Lisp is a reflexive language so that's a very
+;; easy thing to do: inspect the function's form, replace occurences of
+;; <nnfrom> (even in strings) with <nnto>, and you're done.
+
+;; * nndiary-get-new-mail, nndiary-mail-source and nndiary-split-methods:
+;; NNDiary has some experimental parts, in the sense Gnus normally uses only
+;; one mail backends for mail retreival and splitting. This backend is also
+;; an attempt to make it behave differently. For Gnus developpers: as you
+;; can see if you snarf into the code, that was not a very difficult thing
+;; to do. Something should be done about the respooling breakage though.
+
+
+;;; Code:
+
+(require 'nnoo)
+(require 'nnheader)
+(require 'nnmail)
+(eval-when-compile (require 'cl))
+
+(require 'gnus-start)
+(require 'gnus-sum)
+
+;; Compatibility Functions =================================================
+
+(eval-and-compile
+ (if (fboundp 'signal-error)
+ (defun nndiary-error (&rest args)
+ (apply #'signal-error 'nndiary args))
+ (defun nndiary-error (&rest args)
+ (apply #'error args))))
+
+
+;; Backend behavior customization ===========================================
+
+(defgroup nndiary nil
+ "The Gnus Diary backend."
+ :group 'gnus-diary)
+
+(defcustom nndiary-mail-sources
+ `((file :path ,(expand-file-name "~/.nndiary")))
+ "*NNDiary specific mail sources.
+This variable is used by nndiary in place of the standard `mail-sources'
+variable when `nndiary-get-new-mail' is set to non-nil. These sources
+must contain diary messages ONLY."
+ :group 'nndiary
+ :group 'mail-source
+ :type 'sexp)
+
+(defcustom nndiary-split-methods '(("diary" ""))
+ "*NNDiary specific split methods.
+This variable is used by nndiary in place of the standard
+`nnmail-split-methods' variable when `nndiary-get-new-mail' is set to
+non-nil."
+ :group 'nndiary
+ :group 'nnmail-split
+ :type '(choice (repeat :tag "Alist" (group (string :tag "Name") regexp))
+ (function-item nnmail-split-fancy)
+ (function :tag "Other")))
+
+
+(defcustom nndiary-reminders '((0 . day))
+ "*Different times when you want to be reminded of your appointements.
+Diary articles will appear again, as if they'd been just received.
+
+Entries look like (3 . day) which means something like \"Please
+Hortense, would you be so kind as to remind me of my appointments 3 days
+before the date, thank you very much. Anda, hmmm... by the way, are you
+doing anything special tonight ?\".
+
+The units of measure are 'minute 'hour 'day 'week 'month and 'year (no,
+not 'century, sorry).
+
+NOTE: the units of measure actually express dates, not durations: if you
+use 'week, messages will pop up on Sundays at 00:00 (or Mondays if
+`nndiary-week-starts-on-monday' is non nil) and *not* 7 days before the
+appointement, if you use 'month, messages will pop up on the first day of
+each months, at 00:00 and so on.
+
+If you really want to specify a duration (like 24 hours exactly), you can
+use the equivalent in minutes (the smallest unit). A fuzz of 60 seconds
+maximum in the reminder is not that painful, I think. Although this
+scheme might appear somewhat weird at a first glance, it is very powerful.
+In order to make this clear, here are some examples:
+
+- '(0 . day): this is the default value of `nndiary-reminders'. It means
+ pop up the appointements of the day each morning at 00:00.
+
+- '(1 . day): this means pop up the appointements the day before, at 00:00.
+
+- '(6 . hour): for an appointement at 18:30, this would pop up the
+ appointement message at 12:00.
+
+- '(360 . minute): for an appointement at 18:30 and 15 seconds, this would
+ pop up the appointement message at 12:30."
+ :group 'nndiary
+ :type '(repeat (cons :format "%v\n"
+ (integer :format "%v")
+ (choice :format "%[%v(s)%] before...\n"
+ :value day
+ (const :format "%v" minute)
+ (const :format "%v" hour)
+ (const :format "%v" day)
+ (const :format "%v" week)
+ (const :format "%v" month)
+ (const :format "%v" year)))))
+
+(defcustom nndiary-week-starts-on-monday nil
+ "*Whether a week starts on monday (otherwise, sunday)."
+ :type 'boolean
+ :group 'nndiary)
+
+
+(defcustom nndiary-request-create-group-hooks nil
+ "*Hooks to run after `nndiary-request-create-group' is executed.
+The hooks will be called with the full group name as argument."
+ :group 'nndiary
+ :type 'hook)
+
+(defcustom nndiary-request-update-info-hooks nil
+ "*Hooks to run after `nndiary-request-update-info-group' is executed.
+The hooks will be called with the full group name as argument."
+ :group 'nndiary
+ :type 'hook)
+
+(defcustom nndiary-request-accept-article-hooks nil
+ "*Hooks to run before accepting an article.
+Executed near the beginning of `nndiary-request-accept-article'.
+The hooks will be called with the article in the current buffer."
+ :group 'nndiary
+ :type 'hook)
+
+(defcustom nndiary-check-directory-twice t
+ "*If t, check directories twice to avoid NFS failures."
+ :group 'nndiary
+ :type 'boolean)
+
+
+;; Backend declaration ======================================================
+
+;; Well, most of this is nnml clonage.
+
+(nnoo-declare nndiary)
+
+(defvoo nndiary-directory (nnheader-concat gnus-directory "diary/")
+ "Spool directory for the nndiary backend.")
+
+(defvoo nndiary-active-file
+ (expand-file-name "active" nndiary-directory)
+ "Active file for the nndiary backend.")
+
+(defvoo nndiary-newsgroups-file
+ (expand-file-name "newsgroups" nndiary-directory)
+ "Newsgroups description file for the nndiary backend.")
+
+(defvoo nndiary-get-new-mail nil
+ "Whether nndiary gets new mail and split it.
+Contrary to traditional mail backends, this variable can be set to t
+even if your primary mail backend also retreives mail. In such a case,
+NDiary uses its own mail-sources and split-methods.")
+
+(defvoo nndiary-nov-is-evil nil
+ "If non-nil, Gnus will never use nov databases for nndiary groups.
+Using nov databases will speed up header fetching considerably.
+This variable shouldn't be flipped much. If you have, for some reason,
+set this to t, and want to set it to nil again, you should always run
+the `nndiary-generate-nov-databases' command. The function will go
+through all nnml directories and generate nov databases for them
+all. This may very well take some time.")
+
+(defvoo nndiary-prepare-save-mail-hook nil
+ "*Hook run narrowed to an article before saving.")
+
+(defvoo nndiary-inhibit-expiry nil
+ "If non-nil, inhibit expiry.")
+
+\f
+
+(defconst nndiary-version "0.2-b14"
+ "Current Diary backend version.")
+
+(defun nndiary-version ()
+ "Current Diary backend version."
+ (interactive)
+ (message "NNDiary version %s" nndiary-version))
+
+(defvoo nndiary-nov-file-name ".overview")
+
+(defvoo nndiary-current-directory nil)
+(defvoo nndiary-current-group nil)
+(defvoo nndiary-status-string "" )
+(defvoo nndiary-nov-buffer-alist nil)
+(defvoo nndiary-group-alist nil)
+(defvoo nndiary-active-timestamp nil)
+(defvoo nndiary-article-file-alist nil)
+
+(defvoo nndiary-generate-active-function 'nndiary-generate-active-info)
+(defvoo nndiary-nov-buffer-file-name nil)
+(defvoo nndiary-file-coding-system nnmail-file-coding-system)
+
+(defconst nndiary-headers
+ '(("Minute" 0 59)
+ ("Hour" 0 23)
+ ("Dom" 1 31)
+ ("Month" 1 12)
+ ("Year" 1971)
+ ("Dow" 0 6)
+ ("Time-Zone" (("Y" -43200)
+
+ ("X" -39600)
+
+ ("W" -36000)
+
+ ("V" -32400)
+
+ ("U" -28800)
+ ("PST" -28800)
+
+ ("T" -25200)
+ ("MST" -25200)
+ ("PDT" -25200)
+
+ ("S" -21600)
+ ("CST" -21600)
+ ("MDT" -21600)
+
+ ("R" -18000)
+ ("EST" -18000)
+ ("CDT" -18000)
+
+ ("Q" -14400)
+ ("AST" -14400)
+ ("EDT" -14400)
+
+ ("P" -10800)
+ ("ADT" -10800)
+
+ ("O" -7200)
+
+ ("N" -3600)
+
+ ("Z" 0)
+ ("GMT" 0)
+ ("UT" 0)
+ ("UTC" 0)
+ ("WET" 0)
+
+ ("A" 3600)
+ ("CET" 3600)
+ ("MET" 3600)
+ ("MEZ" 3600)
+ ("BST" 3600)
+ ("WEST" 3600)
+
+ ("B" 7200)
+ ("EET" 7200)
+ ("CEST" 7200)
+ ("MEST" 7200)
+ ("MESZ" 7200)
+
+ ("C" 10800)
+
+ ("D" 14400)
+
+ ("E" 18000)
+
+ ("F" 21600)
+
+ ("G" 25200)
+
+ ("H" 28800)
+
+ ("I" 32400)
+ ("JST" 32400)
+
+ ("K" 36000)
+ ("GST" 36000)
+
+ ("L" 39600)
+
+ ("M" 43200)
+ ("NZST" 43200)
+
+ ("NZDT" 46800))))
+ ;; List of NNDiary headers that specify the time spec. Each header name is
+ ;; followed by either two integers (specifying a range of possible values
+ ;; for this header) or one list (specifying all the possible values for this
+ ;; header). In the latter case, the list does NOT include the unspecifyed
+ ;; spec (*).
+ ;; For time zone values, we have symbolic time zone names associated with
+ ;; the (relative) number of seconds ahead GMT.
+ )
+
+(defsubst nndiary-schedule ()
+ (let (head)
+ (condition-case arg
+ (mapcar
+ (lambda (elt)
+ (setq head (nth 0 elt))
+ (nndiary-parse-schedule (nth 0 elt) (nth 1 elt) (nth 2 elt)))
+ nndiary-headers)
+ (t
+ (nnheader-report 'nndiary "X-Diary-%s header parse error: %s."
+ head (cdr arg))
+ nil))
+ ))
+
+;;; Interface functions =====================================================
+
+(nnoo-define-basics nndiary)
+
+(deffoo nndiary-retrieve-headers (sequence &optional group server fetch-old)
+ (when (nndiary-possibly-change-directory group server)
+ (save-excursion
+ (set-buffer nntp-server-buffer)
+ (erase-buffer)
+ (let* ((file nil)
+ (number (length sequence))
+ (count 0)
+ (file-name-coding-system nnmail-pathname-coding-system)
+ beg article
+ (nndiary-check-directory-twice
+ (and nndiary-check-directory-twice
+ ;; To speed up, disable it in some case.
+ (or (not (numberp nnmail-large-newsgroup))
+ (<= number nnmail-large-newsgroup)))))
+ (if (stringp (car sequence))
+ 'headers
+ (if (nndiary-retrieve-headers-with-nov sequence fetch-old)
+ 'nov
+ (while sequence
+ (setq article (car sequence))
+ (setq file (nndiary-article-to-file article))
+ (when (and file
+ (file-exists-p file)
+ (not (file-directory-p file)))
+ (insert (format "221 %d Article retrieved.\n" article))
+ (setq beg (point))
+ (nnheader-insert-head file)
+ (goto-char beg)
+ (if (search-forward "\n\n" nil t)
+ (forward-char -1)
+ (goto-char (point-max))
+ (insert "\n\n"))
+ (insert ".\n")
+ (delete-region (point) (point-max)))
+ (setq sequence (cdr sequence))
+ (setq count (1+ count))
+ (and (numberp nnmail-large-newsgroup)
+ (> number nnmail-large-newsgroup)
+ (zerop (% count 20))
+ (nnheader-message 6 "nndiary: Receiving headers... %d%%"
+ (/ (* count 100) number))))
+
+ (and (numberp nnmail-large-newsgroup)
+ (> number nnmail-large-newsgroup)
+ (nnheader-message 6 "nndiary: Receiving headers...done"))
+
+ (nnheader-fold-continuation-lines)
+ 'headers))))))
+
+(deffoo nndiary-open-server (server &optional defs)
+ (nnoo-change-server 'nndiary server defs)
+ (when (not (file-exists-p nndiary-directory))
+ (ignore-errors (make-directory nndiary-directory t)))
+ (cond
+ ((not (file-exists-p nndiary-directory))
+ (nndiary-close-server)
+ (nnheader-report 'nndiary "Couldn't create directory: %s"
+ nndiary-directory))
+ ((not (file-directory-p (file-truename nndiary-directory)))
+ (nndiary-close-server)
+ (nnheader-report 'nndiary "Not a directory: %s" nndiary-directory))
+ (t
+ (nnheader-report 'nndiary "Opened server %s using directory %s"
+ server nndiary-directory)
+ t)))
+
+(deffoo nndiary-request-regenerate (server)
+ (nndiary-possibly-change-directory nil server)
+ (nndiary-generate-nov-databases server)
+ t)
+
+(deffoo nndiary-request-article (id &optional group server buffer)
+ (nndiary-possibly-change-directory group server)
+ (let* ((nntp-server-buffer (or buffer nntp-server-buffer))
+ (file-name-coding-system nnmail-pathname-coding-system)
+ path gpath group-num)
+ (if (stringp id)
+ (when (and (setq group-num (nndiary-find-group-number id))
+ (cdr
+ (assq (cdr group-num)
+ (nnheader-article-to-file-alist
+ (setq gpath
+ (nnmail-group-pathname
+ (car group-num)
+ nndiary-directory))))))
+ (setq path (concat gpath (int-to-string (cdr group-num)))))
+ (setq path (nndiary-article-to-file id)))
+ (cond
+ ((not path)
+ (nnheader-report 'nndiary "No such article: %s" id))
+ ((not (file-exists-p path))
+ (nnheader-report 'nndiary "No such file: %s" path))
+ ((file-directory-p path)
+ (nnheader-report 'nndiary "File is a directory: %s" path))
+ ((not (save-excursion (let ((nnmail-file-coding-system
+ nndiary-file-coding-system))
+ (nnmail-find-file path))))
+ (nnheader-report 'nndiary "Couldn't read file: %s" path))
+ (t
+ (nnheader-report 'nndiary "Article %s retrieved" id)
+ ;; We return the article number.
+ (cons (if group-num (car group-num) group)
+ (string-to-int (file-name-nondirectory path)))))))
+
+(deffoo nndiary-request-group (group &optional server dont-check)
+ (let ((file-name-coding-system nnmail-pathname-coding-system))
+ (cond
+ ((not (nndiary-possibly-change-directory group server))
+ (nnheader-report 'nndiary "Invalid group (no such directory)"))
+ ((not (file-exists-p nndiary-current-directory))
+ (nnheader-report 'nndiary "Directory %s does not exist"
+ nndiary-current-directory))
+ ((not (file-directory-p nndiary-current-directory))
+ (nnheader-report 'nndiary "%s is not a directory"
+ nndiary-current-directory))
+ (dont-check
+ (nnheader-report 'nndiary "Group %s selected" group)
+ t)
+ (t
+ (nnheader-re-read-dir nndiary-current-directory)
+ (nnmail-activate 'nndiary)
+ (let ((active (nth 1 (assoc group nndiary-group-alist))))
+ (if (not active)
+ (nnheader-report 'nndiary "No such group: %s" group)
+ (nnheader-report 'nndiary "Selected group %s" group)
+ (nnheader-insert "211 %d %d %d %s\n"
+ (max (1+ (- (cdr active) (car active))) 0)
+ (car active) (cdr active) group)))))))
+
+(deffoo nndiary-request-scan (&optional group server)
+ ;; Use our own mail sources and split methods while Gnus doesn't let us have
+ ;; multiple backends for retrieving mail.
+ (let ((mail-sources nndiary-mail-sources)
+ (nnmail-split-methods nndiary-split-methods))
+ (setq nndiary-article-file-alist nil)
+ (nndiary-possibly-change-directory group server)
+ (nnmail-get-new-mail 'nndiary 'nndiary-save-nov nndiary-directory group)))
+
+(deffoo nndiary-close-group (group &optional server)
+ (setq nndiary-article-file-alist nil)
+ t)
+
+(deffoo nndiary-request-create-group (group &optional server args)
+ (nndiary-possibly-change-directory nil server)
+ (nnmail-activate 'nndiary)
+ (cond
+ ((assoc group nndiary-group-alist)
+ t)
+ ((and (file-exists-p (nnmail-group-pathname group nndiary-directory))
+ (not (file-directory-p (nnmail-group-pathname
+ group nndiary-directory))))
+ (nnheader-report 'nndiary "%s is a file"
+ (nnmail-group-pathname group nndiary-directory)))
+ (t
+ (let (active)
+ (push (list group (setq active (cons 1 0)))
+ nndiary-group-alist)
+ (nndiary-possibly-create-directory group)
+ (nndiary-possibly-change-directory group server)
+ (let ((articles (nnheader-directory-articles nndiary-current-directory)))
+ (when articles
+ (setcar active (apply 'min articles))
+ (setcdr active (apply 'max articles))))
+ (nnmail-save-active nndiary-group-alist nndiary-active-file)
+ (run-hook-with-args 'nndiary-request-create-group-hooks
+ (gnus-group-prefixed-name group
+ (list "nndiary" server)))
+ t))
+ ))
+
+(deffoo nndiary-request-list (&optional server)
+ (save-excursion
+ (let ((nnmail-file-coding-system nnmail-active-file-coding-system)
+ (file-name-coding-system nnmail-pathname-coding-system))
+ (nnmail-find-file nndiary-active-file))
+ (setq nndiary-group-alist (nnmail-get-active))
+ t))
+
+(deffoo nndiary-request-newgroups (date &optional server)
+ (nndiary-request-list server))
+
+(deffoo nndiary-request-list-newsgroups (&optional server)
+ (save-excursion
+ (nnmail-find-file nndiary-newsgroups-file)))
+
+(deffoo nndiary-request-expire-articles (articles group &optional server force)
+ (nndiary-possibly-change-directory group server)
+ (let ((active-articles
+ (nnheader-directory-articles nndiary-current-directory))
+ article rest number)
+ (nnmail-activate 'nndiary)
+ ;; Articles not listed in active-articles are already gone,
+ ;; so don't try to expire them.
+ (setq articles (gnus-intersection articles active-articles))
+ (while articles
+ (setq article (nndiary-article-to-file (setq number (pop articles))))
+ (if (and (nndiary-deletable-article-p group number)
+ ;; Don't use nnmail-expired-article-p. Our notion of expiration
+ ;; is a bit peculiar ...
+ (or force (nndiary-expired-article-p article)))
+ (progn
+ ;; Allow a special target group.
+ (unless (eq nnmail-expiry-target 'delete)
+ (with-temp-buffer
+ (nndiary-request-article number group server (current-buffer))
+ (let ((nndiary-current-directory nil))
+ (nnmail-expiry-target-group nnmail-expiry-target group)))
+ (nndiary-possibly-change-directory group server))
+ (nnheader-message 5 "Deleting article %s in %s" number group)
+ (condition-case ()
+ (funcall nnmail-delete-file-function article)
+ (file-error (push number rest)))
+ (setq active-articles (delq number active-articles))
+ (nndiary-nov-delete-article group number))
+ (push number rest)))
+ (let ((active (nth 1 (assoc group nndiary-group-alist))))
+ (when active
+ (setcar active (or (and active-articles
+ (apply 'min active-articles))
+ (1+ (cdr active)))))
+ (nnmail-save-active nndiary-group-alist nndiary-active-file))
+ (nndiary-save-nov)
+ (nconc rest articles)))
+
+(deffoo nndiary-request-move-article
+ (article group server accept-form &optional last)
+ (let ((buf (get-buffer-create " *nndiary move*"))
+ result)
+ (nndiary-possibly-change-directory group server)
+ (nndiary-update-file-alist)
+ (and
+ (nndiary-deletable-article-p group article)
+ (nndiary-request-article article group server)
+ (let (nndiary-current-directory
+ nndiary-current-group
+ nndiary-article-file-alist)
+ (save-excursion
+ (set-buffer buf)
+ (insert-buffer-substring nntp-server-buffer)
+ (setq result (eval accept-form))
+ (kill-buffer (current-buffer))
+ result))
+ (progn
+ (nndiary-possibly-change-directory group server)
+ (condition-case ()
+ (funcall nnmail-delete-file-function
+ (nndiary-article-to-file article))
+ (file-error nil))
+ (nndiary-nov-delete-article group article)
+ (when last
+ (nndiary-save-nov)
+ (nnmail-save-active nndiary-group-alist nndiary-active-file))))
+ result))
+
+(deffoo nndiary-request-accept-article (group &optional server last)
+ (nndiary-possibly-change-directory group server)
+ (nnmail-check-syntax)
+ (run-hooks 'nndiary-request-accept-article-hooks)
+ (when (nndiary-schedule)
+ (let (result)
+ (when nnmail-cache-accepted-message-ids
+ (nnmail-cache-insert (nnmail-fetch-field "message-id")))
+ (if (stringp group)
+ (and
+ (nnmail-activate 'nndiary)
+ (setq result
+ (car (nndiary-save-mail
+ (list (cons group (nndiary-active-number group))))))
+ (progn
+ (nnmail-save-active nndiary-group-alist nndiary-active-file)
+ (and last (nndiary-save-nov))))
+ (and
+ (nnmail-activate 'nndiary)
+ (if (and (not (setq result
+ (nnmail-article-group 'nndiary-active-number)))
+ (yes-or-no-p "Moved to `junk' group; delete article? "))
+ (setq result 'junk)
+ (setq result (car (nndiary-save-mail result))))
+ (when last
+ (nnmail-save-active nndiary-group-alist nndiary-active-file)
+ (when nnmail-cache-accepted-message-ids
+ (nnmail-cache-close))
+ (nndiary-save-nov))))
+ result))
+ )
+
+(deffoo nndiary-request-post (&optional server)
+ (nnmail-do-request-post 'nndiary-request-accept-article server))
+
+(deffoo nndiary-request-replace-article (article group buffer)
+ (nndiary-possibly-change-directory group)
+ (save-excursion
+ (set-buffer buffer)
+ (nndiary-possibly-create-directory group)
+ (let ((chars (nnmail-insert-lines))
+ (art (concat (int-to-string article) "\t"))
+ headers)
+ (when (ignore-errors
+ (nnmail-write-region
+ (point-min) (point-max)
+ (or (nndiary-article-to-file article)
+ (expand-file-name (int-to-string article)
+ nndiary-current-directory))
+ nil (if (nnheader-be-verbose 5) nil 'nomesg))
+ t)
+ (setq headers (nndiary-parse-head chars article))
+ ;; Replace the NOV line in the NOV file.
+ (save-excursion
+ (set-buffer (nndiary-open-nov group))
+ (goto-char (point-min))
+ (if (or (looking-at art)
+ (search-forward (concat "\n" art) nil t))
+ ;; Delete the old NOV line.
+ (delete-region (progn (beginning-of-line) (point))
+ (progn (forward-line 1) (point)))
+ ;; The line isn't here, so we have to find out where
+ ;; we should insert it. (This situation should never
+ ;; occur, but one likes to make sure...)
+ (while (and (looking-at "[0-9]+\t")
+ (< (string-to-int
+ (buffer-substring
+ (match-beginning 0) (match-end 0)))
+ article)
+ (zerop (forward-line 1)))))
+ (beginning-of-line)
+ (nnheader-insert-nov headers)
+ (nndiary-save-nov)
+ t)))))
+
+(deffoo nndiary-request-delete-group (group &optional force server)
+ (nndiary-possibly-change-directory group server)
+ (when force
+ ;; Delete all articles in GROUP.
+ (let ((articles
+ (directory-files
+ nndiary-current-directory t
+ (concat nnheader-numerical-short-files
+ "\\|" (regexp-quote nndiary-nov-file-name) "$")))
+ article)
+ (while articles
+ (setq article (pop articles))
+ (when (file-writable-p article)
+ (nnheader-message 5 "Deleting article %s in %s..." article group)
+ (funcall nnmail-delete-file-function article))))
+ ;; Try to delete the directory itself.
+ (ignore-errors (delete-directory nndiary-current-directory)))
+ ;; Remove the group from all structures.
+ (setq nndiary-group-alist
+ (delq (assoc group nndiary-group-alist) nndiary-group-alist)
+ nndiary-current-group nil
+ nndiary-current-directory nil)
+ ;; Save the active file.
+ (nnmail-save-active nndiary-group-alist nndiary-active-file)
+ t)
+
+(deffoo nndiary-request-rename-group (group new-name &optional server)
+ (nndiary-possibly-change-directory group server)
+ (let ((new-dir (nnmail-group-pathname new-name nndiary-directory))
+ (old-dir (nnmail-group-pathname group nndiary-directory)))
+ (when (ignore-errors
+ (make-directory new-dir t)
+ t)
+ ;; We move the articles file by file instead of renaming
+ ;; the directory -- there may be subgroups in this group.
+ ;; One might be more clever, I guess.
+ (let ((files (nnheader-article-to-file-alist old-dir)))
+ (while files
+ (rename-file
+ (concat old-dir (cdar files))
+ (concat new-dir (cdar files)))
+ (pop files)))
+ ;; Move .overview file.
+ (let ((overview (concat old-dir nndiary-nov-file-name)))
+ (when (file-exists-p overview)
+ (rename-file overview (concat new-dir nndiary-nov-file-name))))
+ (when (<= (length (directory-files old-dir)) 2)
+ (ignore-errors (delete-directory old-dir)))
+ ;; That went ok, so we change the internal structures.
+ (let ((entry (assoc group nndiary-group-alist)))
+ (when entry
+ (setcar entry new-name))
+ (setq nndiary-current-directory nil
+ nndiary-current-group nil)
+ ;; Save the new group alist.
+ (nnmail-save-active nndiary-group-alist nndiary-active-file)
+ t))))
+
+(deffoo nndiary-set-status (article name value &optional group server)
+ (nndiary-possibly-change-directory group server)
+ (let ((file (nndiary-article-to-file article)))
+ (cond
+ ((not (file-exists-p file))
+ (nnheader-report 'nndiary "File %s does not exist" file))
+ (t
+ (with-temp-file file
+ (nnheader-insert-file-contents file)
+ (nnmail-replace-status name value))
+ t))))
+
+\f
+;;; Interface optional functions ============================================
+
+(deffoo nndiary-request-update-info (group info &optional server)
+ (nndiary-possibly-change-directory group)
+ (let ((timestamp (gnus-group-parameter-value (gnus-info-params info)
+ 'timestamp t)))
+ (if (not timestamp)
+ (nnheader-report 'nndiary "Group %s doesn't have a timestamp" group)
+ ;; else
+ ;; Figure out which articles should be re-new'ed
+ (let ((articles (nndiary-flatten (gnus-info-read info) 0))
+ article file unread buf)
+ (save-excursion
+ (setq buf (nnheader-set-temp-buffer " *nndiary update*"))
+ (while (setq article (pop articles))
+ (setq file (concat nndiary-current-directory
+ (int-to-string article)))
+ (and (file-exists-p file)
+ (nndiary-renew-article-p file timestamp)
+ (push article unread)))
+ ;;(message "unread: %s" unread)
+ (sit-for 1)
+ (kill-buffer buf))
+ (setq unread (sort unread '<))
+ (and unread
+ (gnus-info-set-read info (gnus-update-read-articles
+ (gnus-info-group info) unread t)))
+ ))
+ (run-hook-with-args 'nndiary-request-update-info-hooks
+ (gnus-info-group info))
+ t))
+
+
+\f
+;;; Internal functions ======================================================
+
+(defun nndiary-article-to-file (article)
+ (nndiary-update-file-alist)
+ (let (file)
+ (if (setq file (cdr (assq article nndiary-article-file-alist)))
+ (expand-file-name file nndiary-current-directory)
+ ;; Just to make sure nothing went wrong when reading over NFS --
+ ;; check once more.
+ (if nndiary-check-directory-twice
+ (when (file-exists-p
+ (setq file (expand-file-name (number-to-string article)
+ nndiary-current-directory)))
+ (nndiary-update-file-alist t)
+ file)))))
+
+(defun nndiary-deletable-article-p (group article)
+ "Say whether ARTICLE in GROUP can be deleted."
+ (let (path)
+ (when (setq path (nndiary-article-to-file article))
+ (when (file-writable-p path)
+ (or (not nnmail-keep-last-article)
+ (not (eq (cdr (nth 1 (assoc group nndiary-group-alist)))
+ article)))))))
+
+;; Find an article number in the current group given the Message-ID.
+(defun nndiary-find-group-number (id)
+ (save-excursion
+ (set-buffer (get-buffer-create " *nndiary id*"))
+ (let ((alist nndiary-group-alist)
+ number)
+ ;; We want to look through all .overview files, but we want to
+ ;; start with the one in the current directory. It seems most
+ ;; likely that the article we are looking for is in that group.
+ (if (setq number (nndiary-find-id nndiary-current-group id))
+ (cons nndiary-current-group number)
+ ;; It wasn't there, so we look through the other groups as well.
+ (while (and (not number)
+ alist)
+ (or (string= (caar alist) nndiary-current-group)
+ (setq number (nndiary-find-id (caar alist) id)))
+ (or number
+ (setq alist (cdr alist))))
+ (and number
+ (cons (caar alist) number))))))
+
+(defun nndiary-find-id (group id)
+ (erase-buffer)
+ (let ((nov (expand-file-name nndiary-nov-file-name
+ (nnmail-group-pathname group
+ nndiary-directory)))
+ number found)
+ (when (file-exists-p nov)
+ (nnheader-insert-file-contents nov)
+ (while (and (not found)
+ (search-forward id nil t)) ; We find the ID.
+ ;; And the id is in the fourth field.
+ (if (not (and (search-backward "\t" nil t 4)
+ (not (search-backward"\t" (gnus-point-at-bol) t))))
+ (forward-line 1)
+ (beginning-of-line)
+ (setq found t)
+ ;; We return the article number.
+ (setq number
+ (ignore-errors (read (current-buffer))))))
+ number)))
+
+(defun nndiary-retrieve-headers-with-nov (articles &optional fetch-old)
+ (if (or gnus-nov-is-evil nndiary-nov-is-evil)
+ nil
+ (let ((nov (expand-file-name nndiary-nov-file-name
+ nndiary-current-directory)))
+ (when (file-exists-p nov)
+ (save-excursion
+ (set-buffer nntp-server-buffer)
+ (erase-buffer)
+ (nnheader-insert-file-contents nov)
+ (if (and fetch-old
+ (not (numberp fetch-old)))
+ t ; Don't remove anything.
+ (nnheader-nov-delete-outside-range
+ (if fetch-old (max 1 (- (car articles) fetch-old))
+ (car articles))
+ (car (last articles)))
+ t))))))
+
+(defun nndiary-possibly-change-directory (group &optional server)
+ (when (and server
+ (not (nndiary-server-opened server)))
+ (nndiary-open-server server))
+ (if (not group)
+ t
+ (let ((pathname (nnmail-group-pathname group nndiary-directory))
+ (file-name-coding-system nnmail-pathname-coding-system))
+ (when (not (equal pathname nndiary-current-directory))
+ (setq nndiary-current-directory pathname
+ nndiary-current-group group
+ nndiary-article-file-alist nil))
+ (file-exists-p nndiary-current-directory))))
+
+(defun nndiary-possibly-create-directory (group)
+ (let ((dir (nnmail-group-pathname group nndiary-directory)))
+ (unless (file-exists-p dir)
+ (make-directory (directory-file-name dir) t)
+ (nnheader-message 5 "Creating mail directory %s" dir))))
+
+(defun nndiary-save-mail (group-art)
+ "Called narrowed to an article."
+ (let (chars headers)
+ (setq chars (nnmail-insert-lines))
+ (nnmail-insert-xref group-art)
+ (run-hooks 'nnmail-prepare-save-mail-hook)
+ (run-hooks 'nndiary-prepare-save-mail-hook)
+ (goto-char (point-min))
+ (while (looking-at "From ")
+ (replace-match "X-From-Line: ")
+ (forward-line 1))
+ ;; We save the article in all the groups it belongs in.
+ (let ((ga group-art)
+ first)
+ (while ga
+ (nndiary-possibly-create-directory (caar ga))
+ (let ((file (concat (nnmail-group-pathname
+ (caar ga) nndiary-directory)
+ (int-to-string (cdar ga)))))
+ (if first
+ ;; It was already saved, so we just make a hard link.
+ (funcall nnmail-crosspost-link-function first file t)
+ ;; Save the article.
+ (nnmail-write-region (point-min) (point-max) file nil
+ (if (nnheader-be-verbose 5) nil 'nomesg))
+ (setq first file)))
+ (setq ga (cdr ga))))
+ ;; Generate a nov line for this article. We generate the nov
+ ;; line after saving, because nov generation destroys the
+ ;; header.
+ (setq headers (nndiary-parse-head chars))
+ ;; Output the nov line to all nov databases that should have it.
+ (let ((ga group-art))
+ (while ga
+ (nndiary-add-nov (caar ga) (cdar ga) headers)
+ (setq ga (cdr ga))))
+ group-art))
+
+(defun nndiary-active-number (group)
+ "Compute the next article number in GROUP."
+ (let ((active (cadr (assoc group nndiary-group-alist))))
+ ;; The group wasn't known to nndiary, so we just create an active
+ ;; entry for it.
+ (unless active
+ ;; Perhaps the active file was corrupt? See whether
+ ;; there are any articles in this group.
+ (nndiary-possibly-create-directory group)
+ (nndiary-possibly-change-directory group)
+ (unless nndiary-article-file-alist
+ (setq nndiary-article-file-alist
+ (sort
+ (nnheader-article-to-file-alist nndiary-current-directory)
+ 'car-less-than-car)))
+ (setq active
+ (if nndiary-article-file-alist
+ (cons (caar nndiary-article-file-alist)
+ (caar (last nndiary-article-file-alist)))
+ (cons 1 0)))
+ (push (list group active) nndiary-group-alist))
+ (setcdr active (1+ (cdr active)))
+ (while (file-exists-p
+ (expand-file-name (int-to-string (cdr active))
+ (nnmail-group-pathname group nndiary-directory)))
+ (setcdr active (1+ (cdr active))))
+ (cdr active)))
+
+(defun nndiary-add-nov (group article headers)
+ "Add a nov line for the GROUP base."
+ (save-excursion
+ (set-buffer (nndiary-open-nov group))
+ (goto-char (point-max))
+ (mail-header-set-number headers article)
+ (nnheader-insert-nov headers)))
+
+(defsubst nndiary-header-value ()
+ (buffer-substring (match-end 0) (progn (end-of-line) (point))))
+
+(defun nndiary-parse-head (chars &optional number)
+ "Parse the head of the current buffer."
+ (save-excursion
+ (save-restriction
+ (unless (zerop (buffer-size))
+ (narrow-to-region
+ (goto-char (point-min))
+ (if (search-forward "\n\n" nil t) (1- (point)) (point-max))))
+ ;; Fold continuation lines.
+ (goto-char (point-min))
+ (while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t)
+ (replace-match " " t t))
+ ;; Remove any tabs; they are too confusing.
+ (subst-char-in-region (point-min) (point-max) ?\t ? )
+ (let ((headers (nnheader-parse-head t)))
+ (mail-header-set-chars headers chars)
+ (mail-header-set-number headers number)
+ headers))))
+
+(defun nndiary-open-nov (group)
+ (or (cdr (assoc group nndiary-nov-buffer-alist))
+ (let ((buffer (get-buffer-create (format " *nndiary overview %s*"
+ group))))
+ (save-excursion
+ (set-buffer buffer)
+ (set (make-local-variable 'nndiary-nov-buffer-file-name)
+ (expand-file-name
+ nndiary-nov-file-name
+ (nnmail-group-pathname group nndiary-directory)))
+ (erase-buffer)
+ (when (file-exists-p nndiary-nov-buffer-file-name)
+ (nnheader-insert-file-contents nndiary-nov-buffer-file-name)))
+ (push (cons group buffer) nndiary-nov-buffer-alist)
+ buffer)))
+
+(defun nndiary-save-nov ()
+ (save-excursion
+ (while nndiary-nov-buffer-alist
+ (when (buffer-name (cdar nndiary-nov-buffer-alist))
+ (set-buffer (cdar nndiary-nov-buffer-alist))
+ (when (buffer-modified-p)
+ (nnmail-write-region 1 (point-max) nndiary-nov-buffer-file-name
+ nil 'nomesg))
+ (set-buffer-modified-p nil)
+ (kill-buffer (current-buffer)))
+ (setq nndiary-nov-buffer-alist (cdr nndiary-nov-buffer-alist)))))
+
+;;;###autoload
+(defun nndiary-generate-nov-databases (&optional server)
+ "Generate NOV databases in all nndiary directories."
+ (interactive (list (or (nnoo-current-server 'nndiary) "")))
+ ;; Read the active file to make sure we don't re-use articles
+ ;; numbers in empty groups.
+ (nnmail-activate 'nndiary)
+ (unless (nndiary-server-opened server)
+ (nndiary-open-server server))
+ (setq nndiary-directory (expand-file-name nndiary-directory))
+ ;; Recurse down the directories.
+ (nndiary-generate-nov-databases-1 nndiary-directory nil t)
+ ;; Save the active file.
+ (nnmail-save-active nndiary-group-alist nndiary-active-file))
+
+(defun nndiary-generate-nov-databases-1 (dir &optional seen no-active)
+ "Regenerate the NOV database in DIR."
+ (interactive "DRegenerate NOV in: ")
+ (setq dir (file-name-as-directory dir))
+ ;; Only scan this sub-tree if we haven't been here yet.
+ (unless (member (file-truename dir) seen)
+ (push (file-truename dir) seen)
+ ;; We descend recursively
+ (let ((dirs (directory-files dir t nil t))
+ dir)
+ (while (setq dir (pop dirs))
+ (when (and (not (string-match "^\\." (file-name-nondirectory dir)))
+ (file-directory-p dir))
+ (nndiary-generate-nov-databases-1 dir seen))))
+ ;; Do this directory.
+ (let ((files (sort (nnheader-article-to-file-alist dir)
+ 'car-less-than-car)))
+ (if (not files)
+ (let* ((group (nnheader-file-to-group
+ (directory-file-name dir) nndiary-directory))
+ (info (cadr (assoc group nndiary-group-alist))))
+ (when info
+ (setcar info (1+ (cdr info)))))
+ (funcall nndiary-generate-active-function dir)
+ ;; Generate the nov file.
+ (nndiary-generate-nov-file dir files)
+ (unless no-active
+ (nnmail-save-active nndiary-group-alist nndiary-active-file))))))
+
+(eval-when-compile (defvar files))
+(defun nndiary-generate-active-info (dir)
+ ;; Update the active info for this group.
+ (let* ((group (nnheader-file-to-group
+ (directory-file-name dir) nndiary-directory))
+ (entry (assoc group nndiary-group-alist))
+ (last (or (caadr entry) 0)))
+ (setq nndiary-group-alist (delq entry nndiary-group-alist))
+ (push (list group
+ (cons (or (caar files) (1+ last))
+ (max last
+ (or (let ((f files))
+ (while (cdr f) (setq f (cdr f)))
+ (caar f))
+ 0))))
+ nndiary-group-alist)))
+
+(defun nndiary-generate-nov-file (dir files)
+ (let* ((dir (file-name-as-directory dir))
+ (nov (concat dir nndiary-nov-file-name))
+ (nov-buffer (get-buffer-create " *nov*"))
+ chars file headers)
+ (save-excursion
+ ;; Init the nov buffer.
+ (set-buffer nov-buffer)
+ (buffer-disable-undo)
+ (erase-buffer)
+ (set-buffer nntp-server-buffer)
+ ;; Delete the old NOV file.
+ (when (file-exists-p nov)
+ (funcall nnmail-delete-file-function nov))
+ (while files
+ (unless (file-directory-p (setq file (concat dir (cdar files))))
+ (erase-buffer)
+ (nnheader-insert-file-contents file)
+ (narrow-to-region
+ (goto-char (point-min))
+ (progn
+ (search-forward "\n\n" nil t)
+ (setq chars (- (point-max) (point)))
+ (max 1 (1- (point)))))
+ (unless (zerop (buffer-size))
+ (goto-char (point-min))
+ (setq headers (nndiary-parse-head chars (caar files)))
+ (save-excursion
+ (set-buffer nov-buffer)
+ (goto-char (point-max))
+ (nnheader-insert-nov headers)))
+ (widen))
+ (setq files (cdr files)))
+ (save-excursion
+ (set-buffer nov-buffer)
+ (nnmail-write-region 1 (point-max) nov nil 'nomesg)
+ (kill-buffer (current-buffer))))))
+
+(defun nndiary-nov-delete-article (group article)
+ (save-excursion
+ (set-buffer (nndiary-open-nov group))
+ (when (nnheader-find-nov-line article)
+ (delete-region (point) (progn (forward-line 1) (point)))
+ (when (bobp)
+ (let ((active (cadr (assoc group nndiary-group-alist)))
+ num)
+ (when active
+ (if (eobp)
+ (setf (car active) (1+ (cdr active)))
+ (when (and (setq num (ignore-errors (read (current-buffer))))
+ (numberp num))
+ (setf (car active) num)))))))
+ t))
+
+(defun nndiary-update-file-alist (&optional force)
+ (when (or (not nndiary-article-file-alist)
+ force)
+ (setq nndiary-article-file-alist
+ (nnheader-article-to-file-alist nndiary-current-directory))))
+
+
+(defun nndiary-string-to-int (str min &optional max)
+ ;; Like `string-to-int' but barf if STR is not exactly an integer, and not
+ ;; within the specified bounds.
+ ;; Signals are caught by `nndiary-schedule'.
+ (if (not (string-match "^[ \t]*[0-9]+[ \t]*$" str))
+ (nndiary-error "not an integer value")
+ ;; else
+ (let ((val (string-to-int str)))
+ (and (or (< val min)
+ (and max (> val max)))
+ (nndiary-error "value out of range"))
+ val)))
+
+(defun nndiary-parse-schedule-value (str min-or-values max)
+ ;; Parse the schedule string STR, or signal an error.
+ ;; Signals are caught by `nndary-schedule'.
+ (if (string-match "[ \t]*\\*[ \t]*" str)
+ ;; unspecifyed
+ nil
+ ;; specifyed
+ (if (listp min-or-values)
+ ;; min-or-values is values
+ ;; #### NOTE: this is actually only a hack for time zones.
+ (let ((val (and (string-match "[ \t]*\\([^ \t]+\\)[ \t]*" str)
+ (match-string 1 str))))
+ (if (and val (setq val (assoc val min-or-values)))
+ (list (cadr val))
+ (nndiary-error "invalid syntax")))
+ ;; min-or-values is min
+ (mapcar
+ (lambda (val)
+ (let ((res (split-string val "-")))
+ (cond
+ ((= (length res) 1)
+ (nndiary-string-to-int (car res) min-or-values max))
+ ((= (length res) 2)
+ ;; don't know if crontab accepts this, but ensure
+ ;; that BEG is <= END
+ (let ((beg (nndiary-string-to-int (car res) min-or-values max))
+ (end (nndiary-string-to-int (cadr res) min-or-values max)))
+ (cond ((< beg end)
+ (cons beg end))
+ ((= beg end)
+ beg)
+ (t
+ (cons end beg)))))
+ (t
+ (nndiary-error "invalid syntax")))
+ ))
+ (split-string str ",")))
+ ))
+
+;; ### FIXME: remove this function if it's used only once.
+(defun nndiary-parse-schedule (head min-or-values max)
+ ;; Parse the cron-like value of header X-Diary-HEAD in current buffer.
+ ;; - Returns nil if `*'
+ ;; - Otherwise returns a list of integers and/or ranges (BEG . END)
+ ;; The exception is the Timze-Zone value which is always of the form (STR).
+ ;; Signals are caught by `nndary-schedule'.
+ (let ((header (format "^X-Diary-%s: \\(.*\\)$" head)))
+ (goto-char (point-min))
+ (if (not (re-search-forward header nil t))
+ (nndiary-error "header missing")
+ ;; else
+ (nndiary-parse-schedule-value (match-string 1) min-or-values max))
+ ))
+
+(defun nndiary-max (spec)
+ ;; Returns the max of specification SPEC, or nil for permanent schedules.
+ (unless (null spec)
+ (let ((elts spec)
+ (max 0)
+ elt)
+ (while (setq elt (pop elts))
+ (if (integerp elt)
+ (and (> elt max) (setq max elt))
+ (and (> (cdr elt) max) (setq max (cdr elt)))))
+ max)))
+
+(defun nndiary-flatten (spec min &optional max)
+ ;; flatten the spec by expanding ranges to all possible values.
+ (let (flat n)
+ (cond ((null spec)
+ ;; this happens when I flatten something else than one of my
+ ;; schedules (a list of read articles for instance).
+ (unless (null max)
+ (setq n min)
+ (while (<= n max)
+ (push n flat)
+ (setq n (1+ n)))))
+ (t
+ (let ((elts spec)
+ elt)
+ (while (setq elt (pop elts))
+ (if (integerp elt)
+ (push elt flat)
+ ;; else
+ (setq n (car elt))
+ (while (<= n (cdr elt))
+ (push n flat)
+ (setq n (1+ n))))))))
+ flat))
+
+(defun nndiary-unflatten (spec)
+ ;; opposite of flatten: build ranges if possible
+ (setq spec (sort spec '<))
+ (let (min max res)
+ (while (setq min (pop spec))
+ (setq max min)
+ (while (and (car spec) (= (car spec) (1+ max)))
+ (setq max (1+ max))
+ (pop spec))
+ (if (= max min)
+ (setq res (append res (list min)))
+ (setq res (append res (list (cons min max))))))
+ res))
+
+(defun nndiary-compute-reminders (date)
+ ;; Returns a list of times corresponding to the reminders of date DATE.
+ ;; See the comment in `nndiary-reminders' about rounding.
+ (let* ((reminders nndiary-reminders)
+ (date-elts (decode-time date))
+ ;; ### NOTE: out-of-range values are accepted by encode-time. This
+ ;; makes our life easier.
+ (monday (- (nth 3 date-elts)
+ (if nndiary-week-starts-on-monday
+ (if (zerop (nth 6 date-elts))
+ 6
+ (- (nth 6 date-elts) 1))
+ (nth 6 date-elts))))
+ reminder res)
+ ;; remove the DOW and DST entries
+ (setf (nthcdr 6 date-elts) (nthcdr 8 date-elts))
+ (while (setq reminder (pop reminders))
+ (push
+ (cond ((eq (cdr reminder) 'minute)
+ (subtract-time
+ (apply 'encode-time 0 (nthcdr 1 date-elts))
+ (seconds-to-time (* (car reminder) 60.0))))
+ ((eq (cdr reminder) 'hour)
+ (subtract-time
+ (apply 'encode-time 0 0 (nthcdr 2 date-elts))
+ (seconds-to-time (* (car reminder) 3600.0))))
+ ((eq (cdr reminder) 'day)
+ (subtract-time
+ (apply 'encode-time 0 0 0 (nthcdr 3 date-elts))
+ (seconds-to-time (* (car reminder) 86400.0))))
+ ((eq (cdr reminder) 'week)
+ (subtract-time
+ (apply 'encode-time 0 0 0 monday (nthcdr 4 date-elts))
+ (seconds-to-time (* (car reminder) 604800.0))))
+ ((eq (cdr reminder) 'month)
+ (subtract-time
+ (apply 'encode-time 0 0 0 1 (nthcdr 4 date-elts))
+ (seconds-to-time (* (car reminder) 18748800.0))))
+ ((eq (cdr reminder) 'year)
+ (subtract-time
+ (apply 'encode-time 0 0 0 1 1 (nthcdr 5 date-elts))
+ (seconds-to-time (* (car reminder) 400861056.0)))))
+ res))
+ (sort res 'time-less-p)))
+
+(defun nndiary-last-occurence (sched)
+ ;; Returns the last occurence of schedule SCHED as an Emacs time struct, or
+ ;; nil for permanent schedule or errors.
+ (let ((minute (nndiary-max (nth 0 sched)))
+ (hour (nndiary-max (nth 1 sched)))
+ (year (nndiary-max (nth 4 sched)))
+ (time-zone (or (and (nth 6 sched) (car (nth 6 sched)))
+ (current-time-zone))))
+ (when year
+ (or minute (setq minute 59))
+ (or hour (setq hour 23))
+ ;; I'll just compute all possible values and test them by decreasing
+ ;; order until one succeeds. This is probably quide rude, but I got
+ ;; bored in finding a good algorithm for doing that ;-)
+ ;; ### FIXME: remove identical entries.
+ (let ((dom-list (nth 2 sched))
+ (month-list (sort (nndiary-flatten (nth 3 sched) 1 12) '>))
+ (year-list (sort (nndiary-flatten (nth 4 sched) 1971) '>))
+ (dow-list (nth 5 sched)))
+ ;; Special case: an asterisk in one of the days specifications means
+ ;; that only the other should be taken into account. If both are
+ ;; unspecified, you would get all possible days in both.
+ (cond ((null dow-list)
+ ;; this gets all days if dom-list is nil
+ (setq dom-list (nndiary-flatten dom-list 1 31)))
+ ((null dom-list)
+ ;; this also gets all days if dow-list is nil
+ (setq dow-list (nndiary-flatten dow-list 0 6)))
+ (t
+ (setq dom-list (nndiary-flatten dom-list 1 31))
+ (setq dow-list (nndiary-flatten dow-list 0 6))))
+ (or
+ (catch 'found
+ (while (setq year (pop year-list))
+ (let ((months month-list)
+ month)
+ (while (setq month (pop months))
+ ;; Now we must merge the Dows with the Doms. To do that, we
+ ;; have to know which day is the 1st one for this month.
+ ;; Maybe there's simpler, but decode-time(encode-time) will
+ ;; give us the answer.
+ (let ((first (nth 6 (decode-time
+ (encode-time 0 0 0 1 month year
+ time-zone))))
+ (max (cond ((= month 2)
+ (if (date-leap-year-p year) 29 28))
+ ((<= month 7)
+ (if (zerop (% month 2)) 30 31))
+ (t
+ (if (zerop (% month 2)) 31 30))))
+ (doms dom-list)
+ (dows dow-list)
+ day days)
+ ;; first, review the doms to see if they are valid.
+ (while (setq day (pop doms))
+ (and (<= day max)
+ (push day days)))
+ ;; second add all possible dows
+ (while (setq day (pop dows))
+ ;; days start at 1.
+ (setq day (1+ (- day first)))
+ (and (< day 0) (setq day (+ 7 day)))
+ (while (<= day max)
+ (push day days)
+ (setq day (+ 7 day))))
+ ;; Finally, if we have some days, they are valid
+ (when days
+ (sort days '>)
+ (throw 'found
+ (encode-time 0 minute hour
+ (car days) month year time-zone)))
+ )))))
+ ;; There's an upper limit, but we didn't find any last occurence.
+ ;; This means that the schedule is undecidable. This can happen if
+ ;; you happen to say something like "each Feb 31 until 2038".
+ (progn
+ (nnheader-report 'nndiary "Undecidable schedule")
+ nil))
+ ))))
+
+(defun nndiary-next-occurence (sched now)
+ ;; Returns the next occurence of schedule SCHED, starting from time NOW.
+ ;; If there's no next occurence, returns the last one (if any) which is then
+ ;; in the past.
+ (let* ((today (decode-time now))
+ (this-minute (nth 1 today))
+ (this-hour (nth 2 today))
+ (this-day (nth 3 today))
+ (this-month (nth 4 today))
+ (this-year (nth 5 today))
+ (minute-list (sort (nndiary-flatten (nth 0 sched) 0 59) '<))
+ (hour-list (sort (nndiary-flatten (nth 1 sched) 0 23) '<))
+ (dom-list (nth 2 sched))
+ (month-list (sort (nndiary-flatten (nth 3 sched) 1 12) '<))
+ (years (if (nth 4 sched)
+ (sort (nndiary-flatten (nth 4 sched) 1971) '<)
+ t))
+ (dow-list (nth 5 sched))
+ (year (1- this-year))
+ (time-zone (or (and (nth 6 sched) (car (nth 6 sched)))
+ (current-time-zone))))
+ ;; Special case: an asterisk in one of the days specifications means that
+ ;; only the other should be taken into account. If both are unspecified,
+ ;; you would get all possible days in both.
+ (cond ((null dow-list)
+ ;; this gets all days if dom-list is nil
+ (setq dom-list (nndiary-flatten dom-list 1 31)))
+ ((null dom-list)
+ ;; this also gets all days if dow-list is nil
+ (setq dow-list (nndiary-flatten dow-list 0 6)))
+ (t
+ (setq dom-list (nndiary-flatten dom-list 1 31))
+ (setq dow-list (nndiary-flatten dow-list 0 6))))
+ ;; Remove past years.
+ (unless (eq years t)
+ (while (and (car years) (< (car years) this-year))
+ (pop years)))
+ (if years
+ ;; Because we might not be limited in years, we must guard against
+ ;; infinite loops. Appart from cases like Feb 31, there are probably
+ ;; other ones, (no monday XXX 2nd etc). I don't know any algorithm to
+ ;; decide this, so I assume that if we reach 10 years later, the
+ ;; schedule is undecidable.
+ (or
+ (catch 'found
+ (while (if (eq years t)
+ (and (setq year (1+ year))
+ (<= year (+ 10 this-year)))
+ (setq year (pop years)))
+ (let ((months month-list)
+ month)
+ ;; Remove past months for this year.
+ (and (= year this-year)
+ (while (and (car months) (< (car months) this-month))
+ (pop months)))
+ (while (setq month (pop months))
+ ;; Now we must merge the Dows with the Doms. To do that, we
+ ;; have to know which day is the 1st one for this month.
+ ;; Maybe there's simpler, but decode-time(encode-time) will
+ ;; give us the answer.
+ (let ((first (nth 6 (decode-time
+ (encode-time 0 0 0 1 month year
+ time-zone))))
+ (max (cond ((= month 2)
+ (if (date-leap-year-p year) 29 28))
+ ((<= month 7)
+ (if (zerop (% month 2)) 30 31))
+ (t
+ (if (zerop (% month 2)) 31 30))))
+ (doms dom-list)
+ (dows dow-list)
+ day days)
+ ;; first, review the doms to see if they are valid.
+ (while (setq day (pop doms))
+ (and (<= day max)
+ (push day days)))
+ ;; second add all possible dows
+ (while (setq day (pop dows))
+ ;; days start at 1.
+ (setq day (1+ (- day first)))
+ (and (< day 0) (setq day (+ 7 day)))
+ (while (<= day max)
+ (push day days)
+ (setq day (+ 7 day))))
+ ;; Aaaaaaall right. Now we have a valid list of DAYS for
+ ;; this month and this year.
+ (when days
+ (setq days (sort days '<))
+ ;; Remove past days for this year and this month.
+ (and (= year this-year)
+ (= month this-month)
+ (while (and (car days) (< (car days) this-day))
+ (pop days)))
+ (while (setq day (pop days))
+ (let ((hours hour-list)
+ hour)
+ ;; Remove past hours for this year, this month and
+ ;; this day.
+ (and (= year this-year)
+ (= month this-month)
+ (= day this-day)
+ (while (and (car hours)
+ (< (car hours) this-hour))
+ (pop hours)))
+ (while (setq hour (pop hours))
+ (let ((minutes minute-list)
+ minute)
+ ;; Remove past hours for this year, this month,
+ ;; this day and this hour.
+ (and (= year this-year)
+ (= month this-month)
+ (= day this-day)
+ (= hour this-hour)
+ (while (and (car minutes)
+ (< (car minutes) this-minute))
+ (pop minutes)))
+ (while (setq minute (pop minutes))
+ ;; Ouch! Here, we've got a complete valid
+ ;; schedule. It's a good one if it's in the
+ ;; future.
+ (let ((time (encode-time 0 minute hour day
+ month year
+ time-zone)))
+ (and (time-less-p now time)
+ (throw 'found time)))
+ ))))
+ ))
+ )))
+ ))
+ (nndiary-last-occurence sched))
+ ;; else
+ (nndiary-last-occurence sched))
+ ))
+
+(defun nndiary-expired-article-p (file)
+ (with-temp-buffer
+ (if (nnheader-insert-head file)
+ (let ((sched (nndiary-schedule)))
+ ;; An article has expired if its last schedule (if any) is in the
+ ;; past. A permanent schedule never expires.
+ (and sched
+ (setq sched (nndiary-last-occurence sched))
+ (time-less-p sched (current-time))))
+ ;; else
+ (nnheader-report 'nndiary "Could not read file %s" file)
+ nil)
+ ))
+
+(defun nndiary-renew-article-p (file timestamp)
+ (erase-buffer)
+ (if (nnheader-insert-head file)
+ (let ((now (current-time))
+ (sched (nndiary-schedule)))
+ ;; The article should be re-considered as unread if there's a reminder
+ ;; between the group timestamp and the current time.
+ (when (and sched (setq sched (nndiary-next-occurence sched now)))
+ (let ((reminders ;; add the next occurence itself at the end.
+ (append (nndiary-compute-reminders sched) (list sched))))
+ (while (and reminders (time-less-p (car reminders) timestamp))
+ (pop reminders))
+ ;; The reminders might be empty if the last date is in the past,
+ ;; or we've got at least the next occurence itself left. All past
+ ;; dates are renewed.
+ (or (not reminders)
+ (time-less-p (car reminders) now)))
+ ))
+ ;; else
+ (nnheader-report 'nndiary "Could not read file %s" file)
+ nil))
+
+;; The end... ===============================================================
+
+(mapcar
+ (lambda (elt)
+ (let ((header (intern (format "X-Diary-%s" (car elt)))))
+ ;; Required for building NOV databases and some other stuff
+ (add-to-list 'gnus-extra-headers header)
+ (add-to-list 'nnmail-extra-headers header)))
+ nndiary-headers)
+
+(unless (assoc "nndiary" gnus-valid-select-methods)
+ (gnus-declare-backend "nndiary" 'post-mail 'respool 'address))
+
+(provide 'nndiary)
+
+
+;;; nndiary.el ends here
;;; nndoc.el --- single file access for Gnus
-;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;;; Commentary:
+;; For Outlook mail boxes format, see http://mbx2mbox.sourceforge.net/
+
;;; Code:
(require 'nnheader)
"*Type of the file.
One of `mbox', `babyl', `digest', `news', `rnews', `mmdf', `forward',
`rfc934', `rfc822-forward', `mime-parts', `standard-digest',
-`slack-digest', `clari-briefs', `nsmail' or `guess'.")
+`slack-digest', `clari-briefs', `nsmail', `outlook', `oe-dbx',
+`mailman' or `guess'.")
(defvoo nndoc-post-type 'mail
"*Whether the nndoc group is `mail' or `post'.")
(body-end . "\^_")
(body-begin-function . nndoc-babyl-body-begin)
(head-begin-function . nndoc-babyl-head-begin))
- (forward
- (article-begin . "^-+ \\(Start of \\)?forwarded message.*\n+")
- (body-end . "^-+ End \\(of \\)?forwarded message.*$")
- (prepare-body-function . nndoc-unquote-dashes))
(rfc934
(article-begin . "^--.*\n+")
(body-end . "^--.*$")
(prepare-body-function . nndoc-unquote-dashes))
+ (mailman
+ (article-begin . "^--__--__--\n\nMessage:")
+ (body-end . "^--__--__--$")
+ (prepare-body-function . nndoc-unquote-dashes))
(clari-briefs
(article-begin . "^ \\*")
(body-end . "^\t------*[ \t]^*\n^ \\*")
(outlook
(article-begin-function . nndoc-outlook-article-begin)
(body-end . "\0"))
+ (oe-dbx ;; Outlook Express DBX format
+ (dissection-function . nndoc-oe-dbx-dissection)
+ (generate-head-function . nndoc-oe-dbx-generate-head)
+ (generate-article-function . nndoc-oe-dbx-generate-article))
+ (forward
+ (article-begin . "^-+ \\(Start of \\)?forwarded message.*\n+")
+ (body-end . "^-+ End \\(of \\)?forwarded message.*$")
+ (prepare-body-function . nndoc-unquote-dashes))
(guess
(guess . t)
(subtype nil))
(guess . t)
(subtype nil))))
+(defvar nndoc-binary-file-names ".[Dd][Bb][Xx]$"
+ "Regexp for binary nndoc file names.")
+
\f
(defvoo nndoc-file-begin nil)
(defvoo nndoc-first-article nil)
(defvoo nndoc-generate-head-function nil)
(defvoo nndoc-article-transform-function nil)
(defvoo nndoc-article-begin-function nil)
+(defvoo nndoc-generate-article-function nil)
+(defvoo nndoc-dissection-function nil)
(defvoo nndoc-status-string "")
(defvoo nndoc-group-alist nil)
(set-buffer buffer)
(erase-buffer)
(when entry
- (if (stringp article)
- nil
+ (cond
+ ((stringp article) nil)
+ (nndoc-generate-article-function
+ (funcall nndoc-generate-article-function article))
+ (t
(insert-buffer-substring
nndoc-current-buffer (car entry) (nth 1 entry))
(insert "\n")
(funcall nndoc-prepare-body-function))
(when nndoc-article-transform-function
(funcall nndoc-article-transform-function article))
- t)))))
+ t))))))
(deffoo nndoc-request-group (group &optional server dont-check)
"Select news GROUP."
(deffoo nndoc-request-type (group &optional article)
(cond ((not article) 'unknown)
- (nndoc-post-type nndoc-post-type)
- (t 'unknown)))
+ (nndoc-post-type nndoc-post-type)
+ (t 'unknown)))
(deffoo nndoc-close-group (group &optional server)
(nndoc-possibly-change-buffer group server)
(save-excursion
(set-buffer nndoc-current-buffer)
(erase-buffer)
- (if (stringp nndoc-address)
- (nnheader-insert-file-contents nndoc-address)
- (insert-buffer-substring nndoc-address))
- (run-hooks 'nndoc-open-document-hook))))
+ (if (and (stringp nndoc-address)
+ (string-match nndoc-binary-file-names nndoc-address))
+ (let ((coding-system-for-read 'binary))
+ (mm-insert-file-contents nndoc-address))
+ (if (stringp nndoc-address)
+ (nnheader-insert-file-contents nndoc-address)
+ (insert-buffer-substring nndoc-address))
+ (run-hooks 'nndoc-open-document-hook)))))
;; Initialize the nndoc structures according to this new document.
(when (and nndoc-current-buffer
(not nndoc-dissection-alist))
nndoc-body-begin nndoc-body-end-function nndoc-body-end
nndoc-prepare-body-function nndoc-article-transform-function
nndoc-generate-head-function nndoc-body-begin-function
- nndoc-head-begin-function)))
+ nndoc-head-begin-function
+ nndoc-generate-article-function
+ nndoc-dissection-function)))
(while vars
(set (pop vars) nil)))
(let (defs)
t))
(defun nndoc-forward-type-p ()
- (when (and (re-search-forward "^-+ \\(Start of \\)?forwarded message.*\n+"
+ (when (and (re-search-forward "^-+ \\(Start of \\)?forwarded message.*\n+"
nil t)
- (not (re-search-forward "^Subject:.*digest" nil t))
- (not (re-search-backward "^From:" nil t 2))
- (not (re-search-forward "^From:" nil t 2)))
+ (looking-at "[\r\n]*[a-zA-Z][a-zA-Z0-9-]*:"))
t))
(defun nndoc-rfc934-type-p ()
(not (re-search-forward "^From:" nil t 2)))
t))
+(defun nndoc-mailman-type-p ()
+ (when (re-search-forward "^--__--__--\n+" nil t)
+ t))
+
(defun nndoc-rfc822-forward-type-p ()
(save-restriction
(message-narrow-to-head)
;; FIXME: Is JMF the magic of outlook mailbox? -- ShengHuo.
(looking-at "JMF"))
+(defun nndoc-oe-dbx-type-p ()
+ (looking-at (mm-string-as-multibyte "\317\255\022\376")))
+
+(defun nndoc-read-little-endian ()
+ (+ (prog1 (char-after) (forward-char 1))
+ (lsh (prog1 (char-after) (forward-char 1)) 8)
+ (lsh (prog1 (char-after) (forward-char 1)) 16)
+ (lsh (prog1 (char-after) (forward-char 1)) 24)))
+
+(defun nndoc-oe-dbx-decode-block ()
+ (list
+ (nndoc-read-little-endian) ;; this address
+ (nndoc-read-little-endian) ;; next address offset
+ (nndoc-read-little-endian) ;; blocksize
+ (nndoc-read-little-endian))) ;; next address
+
+(defun nndoc-oe-dbx-dissection ()
+ (let ((i 0) blk p tp)
+ (goto-char 60117) ;; 0x0000EAD4+1
+ (setq p (point))
+ (unless (eobp)
+ (setq blk (nndoc-oe-dbx-decode-block)))
+ (while (and blk (> (car blk) 0) (or (zerop (nth 3 blk))
+ (> (nth 3 blk) p)))
+ (push (list (incf i) p nil nil nil 0) nndoc-dissection-alist)
+ (while (and (> (car blk) 0) (> (nth 3 blk) p))
+ (goto-char (1+ (nth 3 blk)))
+ (setq blk (nndoc-oe-dbx-decode-block)))
+ (if (or (<= (car blk) p)
+ (<= (nth 1 blk) 0)
+ (not (zerop (nth 3 blk))))
+ (setq blk nil)
+ (setq tp (+ (car blk) (nth 1 blk) 17))
+ (if (or (<= tp p) (>= tp (point-max)))
+ (setq blk nil)
+ (goto-char tp)
+ (setq p tp
+ blk (nndoc-oe-dbx-decode-block)))))))
+
+(defun nndoc-oe-dbx-generate-article (article &optional head)
+ (let ((entry (cdr (assq article nndoc-dissection-alist)))
+ (cur (current-buffer))
+ (begin (point))
+ blk p)
+ (with-current-buffer nndoc-current-buffer
+ (setq p (car entry))
+ (while (> p (point-min))
+ (goto-char p)
+ (setq blk (nndoc-oe-dbx-decode-block))
+ (setq p (point))
+ (with-current-buffer cur
+ (insert-buffer-substring nndoc-current-buffer p (+ p (nth 2 blk))))
+ (setq p (1+ (nth 3 blk)))))
+ (goto-char begin)
+ (while (re-search-forward "\r$" nil t)
+ (delete-backward-char 1))
+ (when head
+ (goto-char begin)
+ (when (search-forward "\n\n" nil t)
+ (setcar (cddddr entry) (count-lines (point) (point-max)))
+ (delete-region (1- (point)) (point-max))))
+ t))
+
+(defun nndoc-oe-dbx-generate-head (article)
+ (nndoc-oe-dbx-generate-article article 'head))
+
(deffoo nndoc-request-accept-article (group &optional server last)
nil)
-
;;;
;;; Functions for dissecting the documents
;;;
;; Remove blank lines.
(while (eq (following-char) ?\n)
(delete-char 1))
- ;; Find the beginning of the file.
- (when nndoc-file-begin
- (nndoc-search nndoc-file-begin))
- ;; Go through the file.
- (while (if (and first nndoc-first-article)
- (nndoc-search nndoc-first-article)
- (nndoc-article-begin))
- (setq first nil)
- (cond (nndoc-head-begin-function
- (funcall nndoc-head-begin-function))
- (nndoc-head-begin
- (nndoc-search nndoc-head-begin)))
- (if (or (eobp)
- (and nndoc-file-end
- (looking-at nndoc-file-end)))
- (goto-char (point-max))
- (setq head-begin (point))
- (nndoc-search (or nndoc-head-end "^$"))
- (setq head-end (point))
- (if nndoc-body-begin-function
- (funcall nndoc-body-begin-function)
- (nndoc-search (or nndoc-body-begin "^\n")))
- (setq body-begin (point))
- (or (and nndoc-body-end-function
- (funcall nndoc-body-end-function))
- (and nndoc-body-end
- (nndoc-search nndoc-body-end))
- (nndoc-article-begin)
- (progn
- (goto-char (point-max))
- (when nndoc-file-end
- (and (re-search-backward nndoc-file-end nil t)
- (beginning-of-line)))))
- (setq body-end (point))
- (push (list (incf i) head-begin head-end body-begin body-end
- (count-lines body-begin body-end))
- nndoc-dissection-alist))))))
+ (if nndoc-dissection-function
+ (funcall nndoc-dissection-function)
+ ;; Find the beginning of the file.
+ (when nndoc-file-begin
+ (nndoc-search nndoc-file-begin))
+ ;; Go through the file.
+ (while (if (and first nndoc-first-article)
+ (nndoc-search nndoc-first-article)
+ (nndoc-article-begin))
+ (setq first nil)
+ (cond (nndoc-head-begin-function
+ (funcall nndoc-head-begin-function))
+ (nndoc-head-begin
+ (nndoc-search nndoc-head-begin)))
+ (if (or (eobp)
+ (and nndoc-file-end
+ (looking-at nndoc-file-end)))
+ (goto-char (point-max))
+ (setq head-begin (point))
+ (nndoc-search (or nndoc-head-end "^$"))
+ (setq head-end (point))
+ (if nndoc-body-begin-function
+ (funcall nndoc-body-begin-function)
+ (nndoc-search (or nndoc-body-begin "^\n")))
+ (setq body-begin (point))
+ (or (and nndoc-body-end-function
+ (funcall nndoc-body-end-function))
+ (and nndoc-body-end
+ (nndoc-search nndoc-body-end))
+ (nndoc-article-begin)
+ (progn
+ (goto-char (point-max))
+ (when nndoc-file-end
+ (and (re-search-backward nndoc-file-end nil t)
+ (beginning-of-line)))))
+ (setq body-end (point))
+ (push (list (incf i) head-begin head-end body-begin body-end
+ (count-lines body-begin body-end))
+ nndoc-dissection-alist)))))))
(defun nndoc-article-begin ()
(if nndoc-article-begin-function
;;; nndraft.el --- draft article access for Gnus
-;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
(require 'nnmh)
(require 'nnoo)
(require 'mm-util)
-(eval-when-compile
- (require 'cl))
+(eval-when-compile (require 'cl))
(nnoo-declare nndraft
nnmh)
(when (nndraft-request-article article group server (current-buffer))
(message-remove-header "xref")
(message-remove-header "lines")
- (message-remove-header "date")
+ ;; Articles in nndraft:queue are considered as sent messages. The
+ ;; Date field should be the time when they are sent.
+ ;;(message-remove-header "date")
t))
(deffoo nndraft-request-update-info (group info &optional server)
(dolist (n dir)
(unless (file-exists-p
(setq file (expand-file-name (int-to-string n) pathname)))
- (rename-file (let ((buffer-file-name file))
- (make-auto-save-file-name)) file)))))
+ (rename-file (nndraft-auto-save-file-name file) file)))))
(nnoo-parent-function 'nndraft
'nnmh-request-group
(list group server dont-check)))
(let ((file (unless (stringp id)
(nneething-file-name id)))
(nntp-server-buffer (or buffer nntp-server-buffer)))
- (and (stringp file) ; We did not request by Message-ID.
+ (and (stringp file) ; We did not request by Message-ID.
(file-exists-p file) ; The file exists.
(not (file-directory-p file)) ; It's not a dir.
(save-excursion
- (nnmail-find-file file) ; Insert the file in the nntp buf.
+ (nnmail-find-file file) ; Insert the file in the nntp buf.
(unless (nnheader-article-p) ; Either it's a real article...
(goto-char (point-min))
(nneething-make-head
prev)
(while map
(if (and (member (cadr (car map)) files)
- ;; We also remove files that have changed mod times.
+ ;; We also remove files that have changed mod times.
(equal (nth 5 (file-attributes
(nneething-file-name (cadr (car map)))))
(cadr (cdar map))))
(progn
(goto-char (point-min))
(or (and (search-forward "\n\n" nil t)
- (1- (point)))
+ (1- (point)))
(point-max)))
(point-max))
(goto-char (point-min))
(defun nneething-file-name (article)
"Return the file name of ARTICLE."
(let ((dir (file-name-as-directory nneething-address))
- fname)
+ fname)
(if (numberp article)
(if (setq fname (cadr (assq article nneething-map)))
(expand-file-name fname dir)
;;; nnfolder.el --- mail folder access for Gnus
-;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
-;; Author: ShengHuo Zhu <zsh@cs.rochester.edu> (adding NOV)
+;; Author: Simon Josefsson <simon@josefsson.org> (adding MARKS)
+;; ShengHuo Zhu <zsh@cs.rochester.edu> (adding NOV)
;; Scott Byer <byer@mv.us.adobe.com>
;; Lars Magne Ingebrigtsen <larsi@gnus.org>
;; Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
(require 'nnmail)
(require 'nnoo)
(eval-when-compile (require 'cl))
+(require 'gnus)
(require 'gnus-util)
(require 'gnus-range)
(eval-and-compile
+ (autoload 'gnus-article-unpropagatable-p "gnus-sum")
(autoload 'gnus-intersection "gnus-range"))
(nnoo-declare nnfolder)
"The name of the nnfolder NOV directory.
If nil, `nnfolder-directory' is used.")
+(defvoo nnfolder-marks-directory nil
+ "The name of the nnfolder MARKS directory.
+If nil, `nnfolder-directory' is used.")
+
(defvoo nnfolder-active-file
(nnheader-concat nnfolder-directory "active")
"The name of the active file.")
(defvoo nnfolder-save-buffer-hook nil
"Hook run before saving the nnfolder mbox buffer.")
+
(defvoo nnfolder-inhibit-expiry nil
"If non-nil, inhibit expiry.")
(defvoo nnfolder-scantime-alist nil)
(defvoo nnfolder-active-timestamp nil)
(defvoo nnfolder-active-file-coding-system mm-text-coding-system)
-(defvoo nnfolder-active-file-coding-system-for-write
+(defvoo nnfolder-active-file-coding-system-for-write
nnmail-active-file-coding-system)
(defvoo nnfolder-file-coding-system mm-text-coding-system)
(defvoo nnfolder-file-coding-system-for-write nnheader-file-coding-system
"Coding system for save nnfolder file.
-If NIL, NNFOLDER-FILE-CODING-SYSTEM is used.")
+if nil, `nnfolder-file-coding-system' is used.") ; FIXME: fill-in the doc-string of this variable
(defvoo nnfolder-nov-is-evil nil
"If non-nil, Gnus will never generate and use nov databases for mail groups.
(defvar nnfolder-nov-buffer-file-name nil)
+(defvoo nnfolder-marks-is-evil nil
+ "If non-nil, Gnus will never generate and use marks file for mail groups.
+Using marks files makes it possible to backup and restore mail groups
+separately from `.newsrc.eld'. If you have, for some reason, set
+this to t, and want to set it to nil again, you should always remove
+the corresponding marks file (usually base nnfolder file name
+concatenated with `.mrk', but see `nnfolder-marks-file-suffix') for
+the group. Then the marks file will be regenerated properly by Gnus.")
+
+(defvoo nnfolder-marks nil)
+
+(defvoo nnfolder-marks-file-suffix ".mrk")
+
+(defvar nnfolder-marks-modtime (gnus-make-hashtable))
+
\f
;;; Interface functions
'headers
(if (nnfolder-retrieve-headers-with-nov articles fetch-old)
'nov
- (setq articles (gnus-sorted-intersection
+ (setq articles (gnus-sorted-intersection
;; Is ARTICLES sorted?
(sort articles '<)
(nnfolder-existing-articles)))
(unless (or gnus-nov-is-evil nnfolder-nov-is-evil)
(and nnfolder-nov-directory
(gnus-make-directory nnfolder-nov-directory)))
+ (unless nnfolder-marks-is-evil
+ (and nnfolder-marks-directory
+ (gnus-make-directory nnfolder-marks-directory)))
(cond
((not (file-exists-p nnfolder-directory))
(nnfolder-close-server)
(cons nnfolder-current-group article)
(goto-char (point-min))
(cons nnfolder-current-group
- (if (search-forward (concat "\n" nnfolder-article-marker)
+ (if (search-forward (concat "\n" nnfolder-article-marker)
nil t)
(string-to-int
(buffer-substring
(let ((newnum (string-to-number (match-string 0))))
(if (nnmail-within-headers-p)
(push newnum numbers))))
- ;; The article numbers are increasing, so this result is sorted.
+ ;; The article numbers are increasing, so this result is sorted.
(nreverse numbers)))))
(deffoo nnfolder-request-expire-articles
force nnfolder-inhibit-expiry))
(unless (eq nnmail-expiry-target 'delete)
(with-temp-buffer
- (nnfolder-request-article (car maybe-expirable)
+ (nnfolder-request-article (car maybe-expirable)
newsgroup server (current-buffer))
- (let ((nnml-current-directory nil))
+ (let ((nnfolder-current-directory nil))
(nnmail-expiry-target-group
- nnmail-expiry-target newsgroup))))
+ nnmail-expiry-target newsgroup)))
+ (nnfolder-possibly-change-group newsgroup server))
(nnheader-message 5 "Deleting article %d in %s..."
(car maybe-expirable) newsgroup)
(nnfolder-delete-mail)
(goto-char (point-min))
(while (re-search-forward
(concat "^" nnfolder-article-marker)
- (save-excursion (and (search-forward "\n\n" nil t) (point)))
+ (save-excursion (and (search-forward "\n\n" nil t) (point)))
t)
(delete-region (progn (beginning-of-line) (point))
(progn (forward-line 1) (point))))
(goto-char (point-min))
(when (looking-at "X-From-Line: ")
(replace-match "From "))
- (and
- (nnfolder-request-list)
- (save-excursion
- (set-buffer buf)
- (goto-char (point-min))
- (if (search-forward "\n\n" nil t)
- (forward-line -1)
- (goto-char (point-max)))
- (while (re-search-backward (concat "^" nnfolder-article-marker) nil t)
- (delete-region (point) (progn (forward-line 1) (point))))
- (when nnmail-cache-accepted-message-ids
- (nnmail-cache-insert (nnmail-fetch-field "message-id")))
- (setq result (if (stringp group)
- (list (cons group (nnfolder-active-number group)))
- (setq art-group
- (nnmail-article-group 'nnfolder-active-number))))
- (if (and (null result)
- (yes-or-no-p "Moved to `junk' group; delete article? "))
- (setq result 'junk)
- (setq result
- (car (nnfolder-save-mail result)))))
- (when last
- (save-excursion
- (nnfolder-possibly-change-folder (or (caar art-group) group))
- (nnfolder-save-buffer)
- (when nnmail-cache-accepted-message-ids
- (nnmail-cache-close)))))
+ (with-temp-buffer
+ (let ((nnmail-file-coding-system nnfolder-active-file-coding-system)
+ (nntp-server-buffer (current-buffer)))
+ (nnmail-find-file nnfolder-active-file)
+ (setq nnfolder-group-alist (nnmail-parse-active))))
+ (save-excursion
+ (goto-char (point-min))
+ (if (search-forward "\n\n" nil t)
+ (forward-line -1)
+ (goto-char (point-max)))
+ (while (re-search-backward (concat "^" nnfolder-article-marker) nil t)
+ (delete-region (point) (progn (forward-line 1) (point))))
+ (when nnmail-cache-accepted-message-ids
+ (nnmail-cache-insert (nnmail-fetch-field "message-id")))
+ (setq result (if (stringp group)
+ (list (cons group (nnfolder-active-number group)))
+ (setq art-group
+ (nnmail-article-group 'nnfolder-active-number))))
+ (if (and (null result)
+ (yes-or-no-p "Moved to `junk' group; delete article? "))
+ (setq result 'junk)
+ (setq result
+ (car (nnfolder-save-mail result)))))
+ (when last
+ (save-excursion
+ (nnfolder-possibly-change-folder (or (caar art-group) group))
+ (nnfolder-save-buffer)
+ (when nnmail-cache-accepted-message-ids
+ (nnmail-cache-close))))
(nnfolder-save-active nnfolder-group-alist nnfolder-active-file)
(unless result
(nnheader-report 'nnfolder "Couldn't store article"))
(unless (or gnus-nov-is-evil nnfolder-nov-is-evil)
(save-excursion
(set-buffer buffer)
- (let ((headers (nnfolder-parse-head article
+ (let ((headers (nnfolder-parse-head article
(point-min) (point-max))))
(with-current-buffer (nnfolder-open-nov group)
(if (nnheader-find-nov-line article)
;; Delete the file that holds the group.
(ignore-errors
(delete-file (nnfolder-group-pathname group))
- (delete-file (nnfolder-group-nov-pathname group))))
+ (when (file-exists-p (nnfolder-group-nov-pathname group))
+ (delete-file (nnfolder-group-nov-pathname group)))
+ (when (file-exists-p (nnfolder-group-marks-pathname group))
+ (delete-file (nnfolder-group-marks-pathname group)))))
;; Remove the group from all structures.
(setq nnfolder-group-alist
(delq (assoc group nnfolder-group-alist) nnfolder-group-alist)
(let ((new-file (nnfolder-group-pathname new-name)))
(gnus-make-directory (file-name-directory new-file))
(rename-file buffer-file-name new-file)
- (setq new-file (nnfolder-group-nov-pathname new-name))
- (rename-file (nnfolder-group-nov-pathname group)
- new-file))
+ (when (file-exists-p (nnfolder-group-nov-pathname group))
+ (setq new-file (nnfolder-group-nov-pathname new-name))
+ (gnus-make-directory (file-name-directory new-file))
+ (rename-file (nnfolder-group-nov-pathname group) new-file))
+ (when (file-exists-p (nnfolder-group-marks-pathname group))
+ (setq new-file (nnfolder-group-marks-pathname new-name))
+ (gnus-make-directory (file-name-directory new-file))
+ (rename-file (nnfolder-group-marks-pathname group) new-file)))
t)
;; That went ok, so we change the internal structures.
(let ((entry (assoc group nnfolder-group-alist)))
(setq nnfolder-current-buffer nil
nnfolder-current-group nil))
;; Change group.
- (when (and group
- (not (equal group nnfolder-current-group)))
- (let ((file-name-coding-system nnmail-pathname-coding-system))
- (nnmail-activate 'nnfolder)
- (when (and (not (assoc group nnfolder-group-alist))
- (not (file-exists-p
- (nnfolder-group-pathname group))))
- ;; The group doesn't exist, so we create a new entry for it.
- (push (list group (cons 1 0)) nnfolder-group-alist)
- (nnfolder-save-active nnfolder-group-alist nnfolder-active-file))
-
+ (let ((file-name-coding-system nnmail-pathname-coding-system))
+ (when (and group
+ (not (equal group nnfolder-current-group))
+ (progn
+ (nnmail-activate 'nnfolder)
+ (and (assoc group nnfolder-group-alist)
+ (file-exists-p (nnfolder-group-pathname group)))))
(if dont-check
(setq nnfolder-current-group group
nnfolder-current-buffer nil)
(let (inf file)
- ;; If we have to change groups, see if we don't already have the
- ;; folder in memory. If we do, verify the modtime and destroy
- ;; the folder if needed so we can rescan it.
+ ;; If we have to change groups, see if we don't already have
+ ;; the folder in memory. If we do, verify the modtime and
+ ;; destroy the folder if needed so we can rescan it.
(setq nnfolder-current-buffer
(nth 1 (assoc group nnfolder-buffer-alist)))
- ;; If the buffer is not live, make sure it isn't in the alist. If it
- ;; is live, verify that nobody else has touched the file since last
- ;; time.
+ ;; If the buffer is not live, make sure it isn't in the
+ ;; alist. If it is live, verify that nobody else has
+ ;; touched the file since last time.
(when (and nnfolder-current-buffer
(not (gnus-buffer-live-p nnfolder-current-buffer)))
(setq nnfolder-buffer-alist (delq inf nnfolder-buffer-alist)
;; See whether we need to create the new file.
(unless (file-exists-p file)
(gnus-make-directory (file-name-directory file))
- (let ((nnmail-file-coding-system
+ (let ((nnmail-file-coding-system
(or nnfolder-file-coding-system-for-write
nnfolder-file-coding-system-for-write)))
(nnmail-write-region 1 1 file t 'nomesg)))
(goto-char (point-max))
(skip-chars-backward "\n")
(delete-region (point) (point-max))
- (insert "\n\n"))
+ (unless (bobp)
+ (insert "\n\n")))
(defun nnfolder-insert-newsgroup-line (group-art)
(save-excursion
(push (list group (nnfolder-read-folder group))
nnfolder-buffer-alist))))
-;; This method has a problem if you've accidentally let the active list get
-;; out of sync with the files. This could happen, say, if you've
-;; accidentally gotten new mail with something other than Gnus (but why
-;; would _that_ ever happen? :-). In that case, we will be in the middle of
-;; processing the file, ready to add new X-Gnus article number markers, and
-;; we'll run across a message with no ID yet - the active list _may_not_ be
-;; ready for us yet.
-
-;; To handle this, I'm modifying this routine to maintain the maximum ID seen
-;; so far, and when we hit a message with no ID, we will _manually_ scan the
-;; rest of the message looking for any more, possibly higher IDs. We'll
-;; assume the maximum that we find is the highest active. Note that this
-;; shouldn't cost us much extra time at all, but will be a lot less
-;; vulnerable to glitches between the mbox and the active file.
+;; This method has a problem if you've accidentally let the active
+;; list get out of sync with the files. This could happen, say, if
+;; you've accidentally gotten new mail with something other than Gnus
+;; (but why would _that_ ever happen? :-). In that case, we will be
+;; in the middle of processing the file, ready to add new X-Gnus
+;; article number markers, and we'll run across a message with no ID
+;; yet - the active list _may_not_ be ready for us yet.
+
+;; To handle this, I'm modifying this routine to maintain the maximum
+;; ID seen so far, and when we hit a message with no ID, we will
+;; _manually_ scan the rest of the message looking for any more,
+;; possibly higher IDs. We'll assume the maximum that we find is the
+;; highest active. Note that this shouldn't cost us much extra time
+;; at all, but will be a lot less vulnerable to glitches between the
+;; mbox and the active file.
(defun nnfolder-read-folder (group)
(let* ((file (nnfolder-group-pathname group))
(nov (nnfolder-group-nov-pathname group))
(buffer (set-buffer
- (let ((nnheader-file-coding-system
+ (let ((nnheader-file-coding-system
nnfolder-file-coding-system))
(nnheader-find-file-noselect file)))))
+ (mm-enable-multibyte) ;; Use multibyte buffer for future copying.
(if (equal (cadr (assoc group nnfolder-scantime-alist))
(nth 5 (file-attributes file)))
;; This looks up-to-date, so we don't do any scanning.
(setq articles (nreverse articles))))
(goto-char (point-min))
- ;; Anytime the active number is 1 or 0, it is suspect. In that
- ;; case, search the file manually to find the active number. Or,
- ;; of course, if we're being paranoid. (This would also be the
- ;; place to build other lists from the header markers, such as
- ;; expunge lists, etc., if we ever desired to abandon the active
- ;; file entirely for mboxes.)
+ ;; Anytime the active number is 1 or 0, it is suspect. In
+ ;; that case, search the file manually to find the active
+ ;; number. Or, of course, if we're being paranoid. (This
+ ;; would also be the place to build other lists from the
+ ;; header markers, such as expunge lists, etc., if we ever
+ ;; desired to abandon the active file entirely for mboxes.)
(when (or nnfolder-ignore-active-file
novbuf
(< maxid 2))
(with-current-buffer novbuf
(dolist (article articles)
(when (nnheader-find-nov-line article)
- (delete-region (point)
+ (delete-region (point)
(progn (forward-line 1) (point)))))))
(setcar active (max 1 (min minid maxid)))
(setcdr active (max maxid (cdr active)))
(goto-char (point-min)))
- ;; As long as we trust that the user will only insert unmarked mail
- ;; at the end, go to the end and search backwards for the last
- ;; marker. Find the start of that message, and begin to search for
- ;; unmarked messages from there.
+ ;; As long as we trust that the user will only insert
+ ;; unmarked mail at the end, go to the end and search
+ ;; backwards for the last marker. Find the start of that
+ ;; message, and begin to search for unmarked messages from
+ ;; there.
(when (not (or nnfolder-distrust-mbox
(< maxid 2)))
(goto-char (point-max))
;; (goto-char (point-min)))
)
- ;; Keep track of the active number on our own, and insert it back
- ;; into the active list when we're done. Also, prime the pump to
- ;; cut down on the number of searches we do.
+ ;; Keep track of the active number on our own, and insert it
+ ;; back into the active list when we're done. Also, prime
+ ;; the pump to cut down on the number of searches we do.
(unless (nnmail-search-unix-mail-delim)
(goto-char (point-max)))
(setq end (point-marker))
(while (not (= end (point-max)))
(setq start (marker-position end))
(goto-char end)
- ;; There may be more than one "From " line, so we skip past
+ ;; There may be more than one "From " line, so we skip past
;; them.
(while (looking-at delim)
(forward-line 1))
(narrow-to-region start end)
(nnmail-insert-lines)
(nnfolder-insert-newsgroup-line
- (cons nil
+ (cons nil
(setq newnum
- (nnfolder-active-number nnfolder-current-group))))
+ (nnfolder-active-number group))))
(when novbuf
(let ((headers (nnfolder-parse-head newnum (point-min)
- (point-max))))
+ (point-max))))
(with-current-buffer novbuf
(goto-char (point-max))
(nnheader-insert-nov headers))))
(widen)))
(set-marker end nil)
- ;; Make absolutely sure that the active list reflects reality!
+ ;; Make absolutely sure that the active list reflects
+ ;; reality!
(nnfolder-save-active nnfolder-group-alist nnfolder-active-file)
;; Set the scantime for this group.
(setq newscantime (visited-file-modtime))
(if scantime
(setcdr scantime (list newscantime))
- (push (list nnfolder-current-group newscantime)
+ (push (list group newscantime)
nnfolder-scantime-alist))
;; Save nov.
(when novbuf
(interactive)
(nnmail-activate 'nnfolder)
(unless (or gnus-nov-is-evil nnfolder-nov-is-evil)
- (dolist (file (directory-files (or nnfolder-nov-directory
+ (dolist (file (directory-files (or nnfolder-nov-directory
nnfolder-directory)
- t
- (concat
+ t
+ (concat
(regexp-quote nnfolder-nov-file-suffix)
"$")))
(when (not (message-mail-file-mbox-p file))
(ignore-errors
(delete-file file)))))
(let ((files (directory-files nnfolder-directory))
- file)
+ file)
(while (setq file (pop files))
(when (and (not (backup-file-name-p file))
- (message-mail-file-mbox-p
+ (message-mail-file-mbox-p
(nnheader-concat nnfolder-directory file)))
- (let ((oldgroup (assoc file nnfolder-group-alist)))
- (if oldgroup
- (nnheader-message 5 "Refreshing group %s..." file)
- (nnheader-message 5 "Adding group %s..." file))
+ (let ((oldgroup (assoc file nnfolder-group-alist)))
+ (if oldgroup
+ (nnheader-message 5 "Refreshing group %s..." file)
+ (nnheader-message 5 "Adding group %s..." file))
(if oldgroup
(setq nnfolder-group-alist
(delq oldgroup (copy-sequence nnfolder-group-alist))))
- (push (list file (cons 1 0)) nnfolder-group-alist)
- (nnfolder-possibly-change-folder file)
- (nnfolder-possibly-change-group file)
- (nnfolder-close-group file))))
+ (push (list file (cons 1 0)) nnfolder-group-alist)
+ (nnfolder-possibly-change-folder file)
+ (nnfolder-possibly-change-group file)
+ (nnfolder-close-group file))))
(nnheader-message 5 "")))
(defun nnfolder-group-pathname (group)
(when (buffer-modified-p)
(run-hooks 'nnfolder-save-buffer-hook)
(gnus-make-directory (file-name-directory (buffer-file-name)))
- (let ((coding-system-for-write
+ (let ((coding-system-for-write
(or nnfolder-file-coding-system-for-write
nnfolder-file-coding-system)))
(save-buffer)))
(when (buffer-name (cdar nnfolder-nov-buffer-alist))
(set-buffer (cdar nnfolder-nov-buffer-alist))
(when (buffer-modified-p)
- (gnus-make-directory (file-name-directory
+ (gnus-make-directory (file-name-directory
nnfolder-nov-buffer-file-name))
(nnmail-write-region 1 (point-max) nnfolder-nov-buffer-file-name
nil 'nomesg))
"Parse the head of the current buffer."
(let ((buf (current-buffer))
chars)
- (save-excursion
- (unless b
- (setq b (if (nnmail-search-unix-mail-delim-backward)
- (point) (point-min)))
- (forward-line 1)
- (setq e (if (nnmail-search-unix-mail-delim)
- (point) (point-max))))
- (setq chars (- e b))
- (unless (zerop chars)
- (goto-char b)
- (if (search-forward "\n\n" e t) (setq e (1- (point)))))
- (with-temp-buffer
- (insert-buffer-substring buf b e)
- ;; Fold continuation lines.
- (goto-char (point-min))
- (while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t)
- (replace-match " " t t))
- ;; Remove any tabs; they are too confusing.
- (subst-char-in-region (point-min) (point-max) ?\t ? )
- (let ((headers (nnheader-parse-head t)))
- (mail-header-set-chars headers chars)
- (mail-header-set-number headers number)
- headers)))))
+ (save-excursion
+ (unless b
+ (setq b (if (nnmail-search-unix-mail-delim-backward)
+ (point) (point-min)))
+ (forward-line 1)
+ (setq e (if (nnmail-search-unix-mail-delim)
+ (point) (point-max))))
+ (setq chars (- e b))
+ (unless (zerop chars)
+ (goto-char b)
+ (if (search-forward "\n\n" e t) (setq e (1- (point)))))
+ (with-temp-buffer
+ (insert-buffer-substring buf b e)
+ ;; Fold continuation lines.
+ (goto-char (point-min))
+ (while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t)
+ (replace-match " " t t))
+ ;; Remove any tabs; they are too confusing.
+ (subst-char-in-region (point-min) (point-max) ?\t ? )
+ (let ((headers (nnheader-parse-head t)))
+ (mail-header-set-chars headers chars)
+ (mail-header-set-number headers number)
+ headers)))))
(defun nnfolder-add-nov (group article headers)
"Add a nov line for the GROUP base."
(mail-header-set-number headers article)
(nnheader-insert-nov headers)))
+(deffoo nnfolder-request-set-mark (group actions &optional server)
+ (when (and server
+ (not (nnfolder-server-opened server)))
+ (nnfolder-open-server server))
+ (unless nnfolder-marks-is-evil
+ (nnfolder-open-marks group server)
+ (dolist (action actions)
+ (let ((range (nth 0 action))
+ (what (nth 1 action))
+ (marks (nth 2 action)))
+ (assert (or (eq what 'add) (eq what 'del)) t
+ "Unknown request-set-mark action: %s" what)
+ (dolist (mark marks)
+ (setq nnfolder-marks (gnus-update-alist-soft
+ mark
+ (funcall (if (eq what 'add) 'gnus-range-add
+ 'gnus-remove-from-range)
+ (cdr (assoc mark nnfolder-marks)) range)
+ nnfolder-marks)))))
+ (nnfolder-save-marks group server))
+ nil)
+
+(deffoo nnfolder-request-update-info (group info &optional server)
+ ;; Change servers.
+ (when (and server
+ (not (nnfolder-server-opened server)))
+ (nnfolder-open-server server))
+ (when (and (not nnfolder-marks-is-evil) (nnfolder-marks-changed-p group))
+ (nnheader-message 8 "Updating marks for %s..." group)
+ (nnfolder-open-marks group server)
+ ;; Update info using `nnfolder-marks'.
+ (mapcar (lambda (pred)
+ (gnus-info-set-marks
+ info
+ (gnus-update-alist-soft
+ (cdr pred)
+ (cdr (assq (cdr pred) nnfolder-marks))
+ (gnus-info-marks info))
+ t))
+ gnus-article-mark-lists)
+ (let ((seen (cdr (assq 'read nnfolder-marks))))
+ (gnus-info-set-read info
+ (if (and (integerp (car seen))
+ (null (cdr seen)))
+ (list (cons (car seen) (car seen)))
+ seen)))
+ (nnheader-message 8 "Updating marks for %s...done" group))
+ info)
+
+(defun nnfolder-group-marks-pathname (group)
+ "Make pathname for GROUP NOV."
+ (let ((nnfolder-directory (or nnfolder-marks-directory nnfolder-directory)))
+ (concat (nnfolder-group-pathname group) nnfolder-marks-file-suffix)))
+
+(defun nnfolder-marks-changed-p (group)
+ (let ((file (nnfolder-group-marks-pathname group)))
+ (if (null (gnus-gethash file nnfolder-marks-modtime))
+ t ;; never looked at marks file, assume it has changed
+ (not (equal (gnus-gethash file nnfolder-marks-modtime)
+ (nth 5 (file-attributes file)))))))
+
+(defun nnfolder-save-marks (group server)
+ (let ((file-name-coding-system nnmail-pathname-coding-system)
+ (file (nnfolder-group-marks-pathname group)))
+ (condition-case err
+ (progn
+ (with-temp-file file
+ (erase-buffer)
+ (gnus-prin1 nnfolder-marks)
+ (insert "\n"))
+ (gnus-sethash file
+ (nth 5 (file-attributes file))
+ nnfolder-marks-modtime))
+ (error (or (gnus-yes-or-no-p
+ (format "Could not write to %s (%s). Continue? " file err))
+ (error "Cannot write to %s (%s)" err))))))
+
+(defun nnfolder-open-marks (group server)
+ (let ((file (nnfolder-group-marks-pathname group)))
+ (if (file-exists-p file)
+ (condition-case err
+ (with-temp-buffer
+ (gnus-sethash file (nth 5 (file-attributes file))
+ nnfolder-marks-modtime)
+ (nnheader-insert-file-contents file)
+ (setq nnfolder-marks (read (current-buffer)))
+ (dolist (el gnus-article-unpropagated-mark-lists)
+ (setq nnfolder-marks (gnus-remassoc el nnfolder-marks))))
+ (error (or (gnus-yes-or-no-p
+ (format "Error reading nnfolder marks file %s (%s). Continuing will use marks from .newsrc.eld. Continue? " file err))
+ (error "Cannot read nnfolder marks file %s (%s)" file err))))
+ ;; User didn't have a .marks file. Probably first time
+ ;; user of the .marks stuff. Bootstrap it from .newsrc.eld.
+ (let ((info (gnus-get-info
+ (gnus-group-prefixed-name
+ group
+ (gnus-server-to-method (format "nnfolder:%s" server))))))
+ (nnheader-message 7 "Bootstrapping marks for %s..." group)
+ (setq nnfolder-marks (gnus-info-marks info))
+ (push (cons 'read (gnus-info-read info)) nnfolder-marks)
+ (dolist (el gnus-article-unpropagated-mark-lists)
+ (setq nnfolder-marks (gnus-remassoc el nnfolder-marks)))
+ (nnfolder-save-marks group server)))))
+
(provide 'nnfolder)
;;; nnfolder.el ends here
;;; nngateway.el --- posting news via mail gateways
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
(insert mail-header-separator "\n")
(widen)
(let (message-required-mail-headers)
- (funcall message-send-mail-function))
+ (funcall (or message-send-mail-real-function
+ message-send-mail-function)))
t))))
;;; Internal functions
;; Requiring `gnus-util' at compile time creates a circular
;; dependency between nnheader.el and gnus-util.el.
-;(eval-when-compile (require 'gnus-util))
+ ;(eval-when-compile (require 'gnus-util))
(require 'mail-utils)
(require 'mm-util)
(autoload 'gnus-intersection "gnus-range")
(autoload 'gnus-sorted-complement "gnus-range"))
+(defcustom gnus-verbose-backends 7
+ "Integer that says how verbose the Gnus backends should be.
+The higher the number, the more messages the Gnus backends will flash
+to say what it's doing. At zero, the Gnus backends will be totally
+mute; at five, they will display most important messages; and at ten,
+they will keep on jabbering all the time."
+ :group 'gnus-start
+ :type 'integer)
+
+(defcustom gnus-nov-is-evil nil
+ "If non-nil, Gnus backends will never output headers in the NOV format."
+ :group 'gnus-server
+ :type 'boolean)
+
(defvar nnheader-max-head-length 4096
- "*Max length of the head of articles.")
+ "*Max length of the head of articles.
+
+Value is an integer, nil, or t. nil means read in chunks of a file
+indefinitely until a complete head is found\; t means always read the
+entire file immediately, disregarding `nnheader-head-chop-length'.
+
+Integer values will in effect be rounded up to the nearest multiple of
+`nnheader-head-chop-length'.")
(defvar nnheader-head-chop-length 2048
"*Length of each read operation when trying to fetch HEAD headers.")
(autoload 'mail-position-on-field "sendmail")
(autoload 'message-remove-header "message")
(autoload 'gnus-point-at-eol "gnus-util")
- (autoload 'gnus-delete-line "gnus-util" nil nil 'macro)
(autoload 'gnus-buffer-live-p "gnus-util"))
;;; Header access macros.
(concat "fake+none+" (int-to-string (incf nnheader-fake-message-id))))
(defsubst nnheader-fake-message-id-p (id)
- (save-match-data ; regular message-id's are <.*>
+ (save-match-data ; regular message-id's are <.*>
(string-match "\\`fake\\+none\\+[0-9]+\\'" id)))
;; Parsing headers and NOV lines.
(defsubst nnheader-header-value ()
- (buffer-substring (match-end 0) (gnus-point-at-eol)))
+ (skip-chars-forward " \t")
+ (buffer-substring (point) (gnus-point-at-eol)))
(defun nnheader-parse-head (&optional naked)
(let ((case-fold-search t)
;; Subject.
(progn
(goto-char p)
- (if (search-forward "\nsubject: " nil t)
+ (if (search-forward "\nsubject:" nil t)
(nnheader-header-value) "(none)"))
;; From.
(progn
(goto-char p)
- (if (or (search-forward "\nfrom: " nil t)
- (search-forward "\nfrom:" nil t))
+ (if (search-forward "\nfrom:" nil t)
(nnheader-header-value) "(nobody)"))
;; Date.
(progn
(goto-char p)
- (if (search-forward "\ndate: " nil t)
+ (if (search-forward "\ndate:" nil t)
(nnheader-header-value) ""))
;; Message-ID.
(progn
;; References.
(progn
(goto-char p)
- (if (search-forward "\nreferences: " nil t)
+ (if (search-forward "\nreferences:" nil t)
(nnheader-header-value)
;; Get the references from the in-reply-to header if there
;; were no references and the in-reply-to header looks
;; promising.
- (if (and (search-forward "\nin-reply-to: " nil t)
+ (if (and (search-forward "\nin-reply-to:" nil t)
(setq in-reply-to (nnheader-header-value))
(string-match "<[^\n>]+>" in-reply-to))
(let (ref2)
(match-end 0)))
(when (> (length ref2) (length ref))
(setq ref ref2)))
- ref)
+ ref)
nil)))
;; Chars.
0
;; Xref.
(progn
(goto-char p)
- (and (search-forward "\nxref: " nil t)
+ (and (search-forward "\nxref:" nil t)
(nnheader-header-value)))
;; Extra.
(while extra
(goto-char p)
(when (search-forward
- (concat "\n" (symbol-name (car extra)) ": ") nil t)
+ (concat "\n" (symbol-name (car extra)) ":") nil t)
(push (cons (car extra) (nnheader-header-value))
out))
(pop extra))
(setq prev (point))
(while (and (not (numberp (setq num (read cur))))
(not (eobp)))
- (gnus-delete-line))
+ (delete-region (progn (beginning-of-line) (point))
+ (progn (forward-line 1) (point))))
(cond ((> num article)
(setq max (point)))
((< num article)
;; Various cruft the backends and Gnus need to communicate.
(defvar nntp-server-buffer nil)
-(defvar gnus-verbose-backends 7
- "*A number that says how talkative the Gnus backends should be.")
-(defvar gnus-nov-is-evil nil
- "If non-nil, Gnus backends will never output headers in the NOV format.")
+(defvar nntp-process-response nil)
(defvar news-reply-yank-from nil)
(defvar news-reply-yank-message-id nil)
(save-excursion
(unless (gnus-buffer-live-p nntp-server-buffer)
(setq nntp-server-buffer (get-buffer-create " *nntpd*")))
- (mm-enable-multibyte)
(set-buffer nntp-server-buffer)
+ (mm-enable-multibyte)
(erase-buffer)
(kill-all-local-variables)
(setq case-fold-search t) ;Should ignore case.
+ (set (make-local-variable 'nntp-process-response) nil)
t))
;;; Various functions the backends use.
(string-match nnheader-numerical-short-files file)
(string-to-int (match-string 0 file))))
-(defvar nnheader-directory-files-is-safe nil
+(defvar nnheader-directory-files-is-safe
+ (or (eq system-type 'windows-nt)
+ (and (not (featurep 'xemacs))
+ (> emacs-major-version 20)))
"If non-nil, Gnus believes `directory-files' is safe.
It has been reported numerous times that `directory-files' fails with
an alarming frequency on NFS mounted file systems. If it is nil,
(defun nnheader-directory-articles (dir)
"Return a list of all article files in directory DIR."
(mapcar 'nnheader-file-to-number
- (if nnheader-directory-files-is-safe
+ (if nnheader-directory-files-is-safe
(directory-files
dir nil nnheader-numerical-short-files t)
(nnheader-directory-files-safe
(defun nnheader-article-to-file-alist (dir)
"Return an alist of article/file pairs in DIR."
(mapcar (lambda (file) (cons (nnheader-file-to-number file) file))
- (if nnheader-directory-files-is-safe
+ (if nnheader-directory-files-is-safe
(directory-files
dir nil nnheader-numerical-short-files t)
(nnheader-directory-files-safe
;; We translate -- but only the file name. We leave the directory
;; alone.
(if (and (featurep 'xemacs)
- (memq system-type '(win32 w32 mswindows windows-nt)))
+ (memq system-type '(cygwin32 win32 w32 mswindows windows-nt)))
;; This is needed on NT and stuff, because
;; file-name-nondirectory is not enough to split
;; file names, containing ':', e.g.
;; "d:\\Work\\News\\nntp+news.fido7.ru:fido7.ru.gnu.SCORE"
- ;;
+ ;;
;; we are trying to correctly split such names:
;; "d:file.name" -> "a:" "file.name"
;; "aaa:bbb.ccc" -> "" "aaa:bbb.ccc"
;; If not, we translate dots into slashes.
(expand-file-name (mm-encode-coding-string
(nnheader-replace-chars-in-string group ?. ?/)
- nnheader-pathname-coding-system)
+ nnheader-pathname-coding-system)
dir))))
(cond ((null file) "")
((numberp file) (int-to-string file))
(auto-mode-alist (mm-auto-mode-alist))
(default-major-mode 'fundamental-mode)
(enable-local-variables nil)
- (after-insert-file-functions nil)
+ (after-insert-file-functions nil)
(enable-local-eval nil)
(find-file-hooks nil)
(coding-system-for-read nnheader-file-coding-system))
;;; nnheaderxm.el --- making Gnus backends work under XEmacs
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
(provide 'nnheaderxm)
-;;; nnheaderxm.el ends here.
+;;; nnheaderxm.el ends here
;;; Code:
-(eval-and-compile
- (require 'cl)
- (require 'imap))
-
+(require 'imap)
(require 'nnoo)
(require 'nnmail)
(require 'nnheader)
(nnoo-declare nnimap)
-(defconst nnimap-version "nnimap 0.131")
+(defconst nnimap-version "nnimap 1.0")
+
+(defgroup nnimap nil
+ "Reading IMAP mail with Gnus."
+ :group 'gnus)
(defvoo nnimap-address nil
"Address of physical IMAP server. If nil, use the virtual server's name.")
;; Splitting variables
-(defvar nnimap-split-crosspost t
+(defcustom nnimap-split-crosspost t
"If non-nil, do crossposting if several split methods match the mail.
-If nil, the first match found will be used.")
+If nil, the first match found will be used."
+ :group 'nnimap
+ :type 'boolean)
-(defvar nnimap-split-inbox nil
- "*Name of mailbox to split mail from.
+(defcustom nnimap-split-inbox nil
+ "Name of mailbox to split mail from.
Mail is read from this mailbox and split according to rules in
`nnimap-split-rule'.
-This can be a string or a list of strings.")
+This can be a string or a list of strings."
+ :group 'nnimap
+ :type '(choice (string)
+ (repeat string)))
+
+(define-widget 'nnimap-strict-function 'function
+ "This widget only matches values that are functionp.
+
+Warning: This means that a value that is the symbol of a not yet
+loaded function will not match. Use with care."
+ :match 'nnimap-strict-function-match)
-(defvar nnimap-split-rule nil
- "*Mail will be split according to theese rules.
+(defun nnimap-strict-function-match (widget value)
+ "Ignoring WIDGET, match if VALUE is a function."
+ (functionp value))
+
+(defcustom nnimap-split-rule nil
+ "Mail will be split according to theese rules.
Mail is read from mailbox(es) specified in `nnimap-split-inbox'.
everything else in the incoming mailbox, you could do something like
this:
-(setq nnimap-split-rule '((\"INBOX.gnus-imap\" \"From:.*gnus-imap\")
+\(setq nnimap-split-rule '((\"INBOX.gnus-imap\" \"From:.*gnus-imap\")
(\"INBOX.junk\" \"Subject:.*buy\")))
As you can see, `nnimap-split-rule' is a list of lists, where the first
even different split rules in different inboxes on the same server,
the syntax of this variable have been extended along the lines of:
-(setq nnimap-split-rule
+\(setq nnimap-split-rule
'((\"my1server\" (\".*\" ((\"ding\" \"ding@gnus.org\")
- (\"junk\" \"From:.*Simon\")))
- (\"my2server\" (\"INBOX\" nnimap-split-fancy))
- (\"my[34]server\" (\".*\" ((\"private\" \"To:.*Simon\")
- (\"junk\" my-junk-func)))))
+ (\"junk\" \"From:.*Simon\")))
+ (\"my2server\" (\"INBOX\" nnimap-split-fancy))
+ (\"my[34]server\" (\".*\" ((\"private\" \"To:.*Simon\")
+ (\"junk\" my-junk-func)))))
The virtual server name is in fact a regexp, so that the same rules
may apply to several servers. In the example, the servers
\"my3server\" and \"my4server\" both use the same rules. Similarly,
the inbox string is also a regexp. The actual splitting rules are as
before, either a function, or a list with group/regexp or
-group/function elements.")
-
-(defvar nnimap-split-predicate "UNSEEN UNDELETED"
+group/function elements."
+ :group 'nnimap
+ :type '(choice :tag "Rule type"
+ (repeat :menu-tag "Single-server"
+ :tag "Single-server list"
+ (list (string :tag "Mailbox")
+ (choice :tag "Predicate"
+ (regexp :tag "A regexp")
+ (nnimap-strict-function :tag "A function"))))
+ (choice :menu-tag "A function"
+ :tag "A function"
+ (function-item nnimap-split-fancy)
+ (function-item nnmail-split-fancy)
+ (nnimap-strict-function :tag "User-defined function"))
+ (repeat :menu-tag "Multi-server (extended)"
+ :tag "Multi-server list"
+ (list (regexp :tag "Server regexp")
+ (list (regexp :tag "Incoming Mailbox regexp")
+ (repeat :tag "Rules for matching server(s) and mailbox(es)"
+ (list (string :tag "Destination mailbox")
+ (choice :tag "Predicate"
+ (regexp :tag "A Regexp")
+ (nnimap-strict-function :tag "A Function")))))))))
+
+(defcustom nnimap-split-predicate "UNSEEN UNDELETED"
"The predicate used to find articles to split.
If you use another IMAP client to peek on articles but always would
like nnimap to split them once it's started, you could change this to
\"UNDELETED\". Other available predicates are available in
-RFC2060 section 6.4.4.")
-
-(defvar nnimap-split-fancy nil
- "Like `nnmail-split-fancy', which see.")
+RFC2060 section 6.4.4."
+ :group 'nnimap
+ :type 'string)
+
+(defcustom nnimap-split-fancy nil
+ "Like `nnmail-split-fancy', which see."
+ :group 'nnimap
+ :type 'sexp)
+
+(defcustom nnimap-close-asynchronous nil
+ "Close mailboxes asynchronously in `nnimap-close-group'.
+This means that errors cought by nnimap when closing the mailbox will
+not prevent Gnus from updating the group status, which may be harmful.
+However, it increases speed."
+ :type 'boolean
+ :group 'nnimap)
;; Authorization / Privacy variables
everything in the current hierarchy.")
(defvoo nnimap-news-groups nil
- "IMAP support a news-like mode, also known as bulletin board mode, where replies is sent via IMAP instead of SMTP.
+ "IMAP support a news-like mode, also known as bulletin board mode,
+where replies is sent via IMAP instead of SMTP.
This variable should contain a regexp matching groups where you wish
replies to be stored to the mailbox directly.
similar which you wouldn't want to set up a mailing list for, you can
use this to make replies go directly to the group.")
+(defvoo nnimap-expunge-search-string "UID %s NOT SINCE %s"
+ "IMAP search command to use for articles that are to be expired.
+The first %s is replaced by a UID set of articles to search on,
+and the second %s is replaced by a date criterium.
+
+One useful (and perhaps the only useful) value to change this to would
+be `UID %s NOT SENTSINCE %s' to make nnimap use the Date: header
+instead of the internal date of messages. See section 6.4.4 of RFC
+2060 for more information on valid strings.")
+
+(defvoo nnimap-importantize-dormant t
+ "If non-nil, mark \"dormant\" articles as \"ticked\" for other IMAP clients.
+Note that within Gnus, dormant articles will still (only) be
+marked as ticked. This is to make \"dormant\" articles stand out,
+just like \"ticked\" articles, in other IMAP clients.")
+
(defvoo nnimap-server-address nil
"Obsolete. Use `nnimap-address'.")
(defvar nnimap-callback-buffer nil
"Which buffer the asynchronous article prefetch callback should work in.")
(defvar nnimap-server-buffer-alist nil) ;; Map server name to buffers.
-(defvar nnimap-current-server nil) ;; Current server
-(defvar nnimap-server-buffer nil) ;; Current servers' buffer
+(defvar nnimap-current-server nil) ;; Current server
+(defvar nnimap-server-buffer nil) ;; Current servers' buffer
\f
(new-uidvalidity (imap-mailbox-get 'uidvalidity))
(old-uidvalidity (gnus-group-get-parameter gnusgroup 'uidvalidity))
(dir (file-name-as-directory (expand-file-name nnimap-directory)))
- (nameuid (nnheader-translate-file-chars
- (concat nnimap-nov-file-name
- (if (equal server "")
- "unnamed"
- server) "." group "." old-uidvalidity
- nnimap-nov-file-name-suffix) t))
- (file (if (or nnmail-use-long-file-names
+ (nameuid (nnheader-translate-file-chars
+ (concat nnimap-nov-file-name
+ (if (equal server "")
+ "unnamed"
+ server) "." group "." old-uidvalidity
+ nnimap-nov-file-name-suffix) t))
+ (file (if (or nnmail-use-long-file-names
(file-exists-p (expand-file-name nameuid dir)))
(expand-file-name nameuid dir)
(expand-file-name
maxuid (if maxuid (max maxuid uid) uid)))
'UID))
(list (imap-mailbox-get 'exists) minuid maxuid)))))
-
+
(defun nnimap-possibly-change-group (group &optional server)
"Make GROUP the current group, and SERVER the current server."
(when (nnimap-possibly-change-server server)
(if (or (nnimap-verify-uidvalidity
group (or server nnimap-current-server))
(zerop (imap-mailbox-get 'exists group))
+ t ;; for OGnus to see if ignoring uidvalidity
+ ;; changes has any bad effects.
(yes-or-no-p
(format
"nnimap: Group %s is not uidvalid. Continue? " group)))
imap-current-mailbox
(imap-mailbox-unselect)
- (error "nnimap: Group %s is not uid-valid." group))
+ (error "nnimap: Group %s is not uid-valid" group))
(nnheader-report 'nnimap (imap-error-text)))))))
(defun nnimap-replace-whitespace (string)
(defun nnimap-group-overview-filename (group server)
"Make pathname for GROUP on SERVER."
(let* ((dir (file-name-as-directory (expand-file-name nnimap-directory)))
- (uidvalidity (gnus-group-get-parameter
- (gnus-group-prefixed-name
- group (gnus-server-to-method
- (format "nnimap:%s" server)))
- 'uidvalidity))
- (name (nnheader-translate-file-chars
- (concat nnimap-nov-file-name
- (if (equal server "")
- "unnamed"
- server) "." group nnimap-nov-file-name-suffix) t))
- (nameuid (nnheader-translate-file-chars
- (concat nnimap-nov-file-name
- (if (equal server "")
- "unnamed"
- server) "." group "." uidvalidity
- nnimap-nov-file-name-suffix) t))
- (oldfile (if (or nnmail-use-long-file-names
- (file-exists-p (expand-file-name name dir)))
- (expand-file-name name dir)
- (expand-file-name
- (mm-encode-coding-string
- (nnheader-replace-chars-in-string name ?. ?/)
- nnmail-pathname-coding-system)
- dir)))
- (newfile (if (or nnmail-use-long-file-names
- (file-exists-p (expand-file-name nameuid dir)))
- (expand-file-name nameuid dir)
- (expand-file-name
- (mm-encode-coding-string
- (nnheader-replace-chars-in-string nameuid ?. ?/)
- nnmail-pathname-coding-system)
- dir))))
+ (uidvalidity (gnus-group-get-parameter
+ (gnus-group-prefixed-name
+ group (gnus-server-to-method
+ (format "nnimap:%s" server)))
+ 'uidvalidity))
+ (name (nnheader-translate-file-chars
+ (concat nnimap-nov-file-name
+ (if (equal server "")
+ "unnamed"
+ server) "." group nnimap-nov-file-name-suffix) t))
+ (nameuid (nnheader-translate-file-chars
+ (concat nnimap-nov-file-name
+ (if (equal server "")
+ "unnamed"
+ server) "." group "." uidvalidity
+ nnimap-nov-file-name-suffix) t))
+ (oldfile (if (or nnmail-use-long-file-names
+ (file-exists-p (expand-file-name name dir)))
+ (expand-file-name name dir)
+ (expand-file-name
+ (mm-encode-coding-string
+ (nnheader-replace-chars-in-string name ?. ?/)
+ nnmail-pathname-coding-system)
+ dir)))
+ (newfile (if (or nnmail-use-long-file-names
+ (file-exists-p (expand-file-name nameuid dir)))
+ (expand-file-name nameuid dir)
+ (expand-file-name
+ (mm-encode-coding-string
+ (nnheader-replace-chars-in-string nameuid ?. ?/)
+ nnmail-pathname-coding-system)
+ dir))))
(when (and (file-exists-p oldfile) (not (file-exists-p newfile)))
(message "nnimap: Upgrading novcache filename...")
(sit-for 1)
(nnimap-retrieve-headers-from-server
(cons (1+ (cdr cached)) high) group server))
(when nnimap-prune-cache
- ;; remove nov's for articles which has expired on server
+ ;; remove nov's for articles which has expired on server
(goto-char (point-min))
(dolist (uid (gnus-set-difference articles uids))
- (when (re-search-forward (format "^%d\t" uid) nil t)
- (gnus-delete-line)))))
+ (when (re-search-forward (format "^%d\t" uid) nil t)
+ (gnus-delete-line)))))
;; nothing cached, fetch whole range from server
(nnimap-retrieve-headers-from-server
(cons low high) group server))
(port (if nnimap-server-port
(int-to-string nnimap-server-port)
"imap"))
- (alist (gnus-netrc-machine list (or nnimap-server-address
- nnimap-address server)
- port "imap"))
+ (alist (gnus-netrc-machine list (or nnimap-server-address
+ nnimap-address server)
+ port "imap"))
(user (gnus-netrc-get alist "login"))
(passwd (gnus-netrc-get alist "password")))
(if (imap-authenticate user passwd nnimap-server-buffer)
(cadr (assq 'nnimap-server-address defs))) defs)
(push (list 'nnimap-address server) defs)))
(nnoo-change-server 'nnimap server defs)
+ (or nnimap-server-buffer
+ (setq nnimap-server-buffer (cadr (assq 'nnimap-server-buffer defs))))
(with-current-buffer (get-buffer-create nnimap-server-buffer)
(nnoo-change-server 'nnimap server defs))
(or (and nnimap-server-buffer
(insert
(with-current-buffer nnimap-server-buffer
(nnimap-demule
- (if (imap-capability 'IMAP4rev1)
- ;; xxx don't just use car? alist doesn't contain
- ;; anything else now, but it might...
- (nth 2 (car (imap-message-get (imap-current-message) 'BODYDETAIL)))
- (imap-message-get (imap-current-message) 'RFC822)))))
+ (if (imap-capability 'IMAP4rev1)
+ ;; xxx don't just use car? alist doesn't contain
+ ;; anything else now, but it might...
+ (nth 2 (car (imap-message-get (imap-current-message) 'BODYDETAIL)))
+ (imap-message-get (imap-current-message) 'RFC822)))))
(nnheader-ms-strip-cr)
(funcall nnimap-callback-callback-function t)))
(defun nnimap-request-article-part (article part prop &optional
- group server to-buffer detail)
+ group server to-buffer detail)
(when (nnimap-possibly-change-group group server)
(let ((article (if (stringp article)
(car-safe (imap-search
(if (not nnheader-callback-function)
(with-current-buffer (or to-buffer nntp-server-buffer)
(erase-buffer)
- (let ((data (imap-fetch article part prop nil
- nnimap-server-buffer)))
- (insert (nnimap-demule (if detail
- (nth 2 (car data))
- data))))
- (nnheader-ms-strip-cr)
+ (let ((data (imap-fetch article part prop nil
+ nnimap-server-buffer)))
+ (insert (nnimap-demule (if detail
+ (nth 2 (car data))
+ data))))
+ (nnheader-ms-strip-cr)
(gnus-message 10 "nnimap: Fetching (part of) article %d...done"
article)
(if (bobp)
(when (and (imap-opened)
(nnimap-possibly-change-group group server))
(case nnimap-expunge-on-close
- ('always (imap-mailbox-expunge)
- (imap-mailbox-close))
- ('ask (if (and (imap-search "DELETED")
+ (always (imap-mailbox-expunge nnimap-close-asynchronous)
+ (imap-mailbox-close nnimap-close-asynchronous))
+ (ask (if (and (imap-search "DELETED")
(gnus-y-or-n-p (format
"Expunge articles in group `%s'? "
imap-current-mailbox)))
- (progn (imap-mailbox-expunge)
- (imap-mailbox-close))
+ (progn (imap-mailbox-expunge nnimap-close-asynchronous)
+ (imap-mailbox-close nnimap-close-asynchronous))
(imap-mailbox-unselect)))
(t (imap-mailbox-unselect)))
(not imap-current-mailbox))))
(let ((info (nnimap-find-minmax-uid mbx 'examine)))
(when info
(with-current-buffer nntp-server-buffer
- (insert (format "\"%s\" %d %d y\n"
- mbx (or (nth 2 info) 0)
- (max 1 (or (nth 1 info) 1)))))))))))
+ (insert (format "\"%s\" %d %d y\n"
+ mbx (or (nth 2 info) 0)
+ (max 1 (or (nth 1 info) 1)))))))))))
(gnus-message 5 "nnimap: Generating active list%s...done"
(if (> (length server) 0) (concat " for " server) ""))
t))
(deffoo nnimap-request-post (&optional server)
(let ((success t))
(dolist (mbx (message-unquote-tokens
- (message-tokenize-header
- (message-fetch-field "Newsgroups") ", ")) success)
+ (message-tokenize-header
+ (message-fetch-field "Newsgroups") ", ")) success)
(let ((to-newsgroup (gnus-group-prefixed-name mbx gnus-command-method)))
(or (gnus-active to-newsgroup)
(gnus-activate-group to-newsgroup)
(or (member "\\NoSelect"
(imap-mailbox-get 'list-flags group nnimap-server-buffer))
(let ((info (nnimap-find-minmax-uid group 'examine)))
+ (when (> (or (imap-mailbox-get 'recent group
+ nnimap-server-buffer) 0)
+ 0)
+ (push (list (cons group 0)) nnmail-split-history))
(insert (format "\"%s\" %d %d y\n" group
(or (nth 2 info) 0)
(max 1 (or (nth 1 info) 1))))))))
(deffoo nnimap-request-update-info-internal (group info &optional server)
(when (nnimap-possibly-change-group group server)
- (when info;; xxx what does this mean? should we create a info?
+ (when info ;; xxx what does this mean? should we create a info?
(with-current-buffer nnimap-server-buffer
(gnus-message 5 "nnimap: Updating info for %s..."
(gnus-info-group info))
-
+
(when (nnimap-mark-permanent-p 'read)
(let (seen unseen)
;; read info could contain articles marked unread by other
(gnus-info-set-read info seen)))
(mapcar (lambda (pred)
- (when (and (nnimap-mark-permanent-p (cdr pred))
- (member (nnimap-mark-to-flag (cdr pred))
- (imap-mailbox-get 'flags)))
+ (when (or (eq (cdr pred) 'recent)
+ (and (nnimap-mark-permanent-p (cdr pred))
+ (member (nnimap-mark-to-flag (cdr pred))
+ (imap-mailbox-get 'flags))))
(gnus-info-set-marks
info
- (nnimap-update-alist-soft
+ (gnus-update-alist-soft
(cdr pred)
(gnus-compress-sequence
(imap-search (nnimap-mark-to-predicate (cdr pred))))
t)))
gnus-article-mark-lists)
- ;; nnimap mark dormant article as ticked too (for other clients)
- ;; so we remove that mark for gnus since we support dormant
- (gnus-info-set-marks
- info
- (nnimap-update-alist-soft
- 'tick
- (gnus-remove-from-range
- (cdr-safe (assoc 'tick (gnus-info-marks info)))
- (cdr-safe (assoc 'dormant (gnus-info-marks info))))
- (gnus-info-marks info))
- t)
-
+ (when nnimap-importantize-dormant
+ ;; nnimap mark dormant article as ticked too (for other clients)
+ ;; so we remove that mark for gnus since we support dormant
+ (gnus-info-set-marks
+ info
+ (gnus-update-alist-soft
+ 'tick
+ (gnus-remove-from-range
+ (cdr-safe (assoc 'tick (gnus-info-marks info)))
+ (cdr-safe (assoc 'dormant (gnus-info-marks info))))
+ (gnus-info-marks info))
+ t))
+
(gnus-message 5 "nnimap: Updating info for %s...done"
(gnus-info-group info))
(what (nth 1 action))
(cmdmarks (nth 2 action))
marks)
+ ;; bookmark can't be stored (not list/range
+ (setq cmdmarks (delq 'bookmark cmdmarks))
+ ;; killed can't be stored (not list/range
+ (setq cmdmarks (delq 'killed cmdmarks))
+ ;; unsent are for nndraft groups only
+ (setq cmdmarks (delq 'unsent cmdmarks))
;; cache flags are pointless on the server
(setq cmdmarks (delq 'cache cmdmarks))
- ;; flag dormant articles as ticked
- (if (memq 'dormant cmdmarks)
- (setq cmdmarks (cons 'tick cmdmarks)))
+ ;; seen flags are local to each gnus
+ (setq cmdmarks (delq 'seen cmdmarks))
+ ;; recent marks can't be set
+ (setq cmdmarks (delq 'recent cmdmarks))
+ (when nnimap-importantize-dormant
+ ;; flag dormant articles as ticked
+ (if (memq 'dormant cmdmarks)
+ (setq cmdmarks (cons 'tick cmdmarks))))
;; remove stuff we are forbidden to store
(mapcar (lambda (mark)
(if (imap-message-flag-permanent-p
(setq regrepp (string-match "\\\\[0-9&]" group))
(re-search-forward regexp nil t))
(funcall regexp group))
- ;; Don't enter the article into the same group twice.
+ ;; Don't enter the article into the same group twice.
(not (assoc group to-groups)))
(push (if regrepp
(nnmail-expand-newtext group)
to-groups)
(or nnimap-split-crosspost
(throw 'split-done to-groups))))))))))
-
+
(defun nnimap-assoc-match (key alist)
(let (element)
(while (and alist (not element))
(defun nnimap-split-find-rule (server inbox)
(if (and (listp nnimap-split-rule) (listp (car nnimap-split-rule))
- (list (cdar nnimap-split-rule)) (listp (cadar nnimap-split-rule)))
+ (list (cdar nnimap-split-rule)) (listp (cadar nnimap-split-rule)))
;; extended format
- (cadr (nnimap-assoc-match inbox (cdr (nnimap-assoc-match
+ (cadr (nnimap-assoc-match inbox (cdr (nnimap-assoc-match
server nnimap-split-rule))))
nnimap-split-rule))
(let (rule inbox removeorig (inboxes (nnimap-split-find-inbox server)))
;; iterate over inboxes
(while (and (setq inbox (pop inboxes))
- (nnimap-possibly-change-group inbox));; SELECT
+ (nnimap-possibly-change-group inbox)) ;; SELECT
;; find split rule for this server / inbox
(when (setq rule (nnimap-split-find-rule server inbox))
;; iterate over articles
;; copy article to right group(s)
(setq removeorig nil)
(dolist (to-group (nnimap-split-to-groups rule))
- (if (imap-message-copy (number-to-string article)
- to-group nil 'nocopyuid)
- (progn
- (message "IMAP split moved %s:%s:%d to %s" server inbox
- article to-group)
- (setq removeorig t)
- ;; Add the group-art list to the history list.
- (push (list (cons to-group 0)) nnmail-split-history))
- (message "IMAP split failed to move %s:%s:%d to %s" server
- inbox article to-group)))
+ (cond ((eq to-group 'junk)
+ (message "IMAP split removed %s:%s:%d" server inbox
+ article)
+ (setq removeorig t))
+ ((imap-message-copy (number-to-string article)
+ to-group nil 'nocopyuid)
+ (message "IMAP split moved %s:%s:%d to %s" server
+ inbox article to-group)
+ (setq removeorig t)
+ ;; Add the group-art list to the history list.
+ (push (list (cons to-group 0)) nnmail-split-history))
+ (t
+ (message "IMAP split failed to move %s:%s:%d to %s"
+ server inbox article to-group))))
;; remove article if it was successfully copied somewhere
(and removeorig
(imap-message-flags-add (format "%d" article)
"\\Seen \\Deleted")))))
- (when (imap-mailbox-select inbox);; just in case
+ (when (imap-mailbox-select inbox) ;; just in case
;; todo: UID EXPUNGE (if available) to remove splitted articles
(imap-mailbox-expunge)
(imap-mailbox-close)))
(nnimap-before-find-minmax-bugworkaround)
(dolist (pattern (nnimap-pattern-to-list-arguments
nnimap-list-pattern))
- (dolist (mbx (imap-mailbox-lsub "*" (car pattern) nil
+ (dolist (mbx (imap-mailbox-lsub "*" (car pattern) nil
nnimap-server-buffer))
(or (catch 'found
(dolist (mailbox (imap-mailbox-get 'list-flags mbx
nil)
(let ((info (nnimap-find-minmax-uid mbx 'examine)))
(when info
- (insert (format "\"%s\" %d %d y\n"
- mbx (or (nth 2 info) 0)
- (max 1 (or (nth 1 info) 1)))))))))
+ (insert (format "\"%s\" %d %d y\n"
+ mbx (or (nth 2 info) 0)
+ (max 1 (or (nth 1 info) 1)))))))))
(gnus-message 5 "nnimap: Listing subscribed mailboxes%s%s...done"
(if (> (length server) 0) " on " "") server))
t))
-
+
(deffoo nnimap-request-create-group (group &optional server args)
(when (nnimap-possibly-change-server server)
(or (imap-mailbox-status group 'uidvalidity nnimap-server-buffer)
(defun nnimap-date-days-ago (daysago)
"Return date, in format \"3-Aug-1998\", for DAYSAGO days ago."
- (let ((date (format-time-string "%d-%b-%Y"
- (nnimap-time-substract
- (current-time)
- (days-to-time daysago)))))
+ (let* ((time (nnimap-time-substract (current-time) (days-to-time daysago)))
+ (date (format-time-string
+ (format "%%d-%s-%%Y"
+ (capitalize (car (rassoc (nth 4 (decode-time time))
+ parse-time-months))))
+ time)))
(if (eq ?0 (string-to-char date))
(substring date 1)
date)))
(defun nnimap-expiry-target (arts group server)
(unless (eq nnmail-expiry-target 'delete)
- (with-current-buffer nntp-server-buffer
+ (with-temp-buffer
(dolist (art (gnus-uncompress-sequence arts))
- (nnimap-request-article art group server)
+ (nnimap-request-article art group server (current-buffer))
;; hints for optimization in `nnimap-request-accept-article'
(let ((nnimap-current-move-article art)
(nnimap-current-move-group group)
(nnimap-current-move-server server))
- (nnmail-expiry-target-group nnmail-expiry-target group))))))
+ (nnmail-expiry-target-group nnmail-expiry-target group))))
+ ;; It is not clear if `nnmail-expiry-target' somehow cause the
+ ;; current group to be changed or not, so we make sure here.
+ (nnimap-possibly-change-group group server)))
;; Notice that we don't actually delete anything, we just mark them deleted.
(deffoo nnimap-request-expire-articles (articles group &optional server force)
(setq articles nil)))
((numberp days)
(let ((oldarts (imap-search
- (format "UID %s NOT SINCE %s"
+ (format nnimap-expunge-search-string
(imap-range-to-message-set artseq)
(nnimap-date-days-ago days))))
(imap-fetch-data-hook
(setq result (eval accept-form))
(kill-buffer buf)
result)
- (nnimap-request-expire-articles (list article) group server t))
+ (imap-message-flags-add
+ (imap-range-to-message-set (list article))
+ "\\Deleted" 'silent nnimap-server-buffer))
result))))
-
+
(deffoo nnimap-request-accept-article (group &optional server last)
(when (nnimap-possibly-change-server server)
(let (uid)
(if (setq uid
(if (string= nnimap-current-server nnimap-current-move-server)
- ;; moving article within same server, speed it up...
+ ;; moving article within same server, speed it up...
(and (nnimap-possibly-change-group
nnimap-current-move-group)
(imap-message-copy (number-to-string
nnimap-server-buffer))
(with-current-buffer (current-buffer)
(goto-char (point-min))
- ;; remove any 'From blabla' lines, some IMAP servers
+ ;; remove any 'From blabla' lines, some IMAP servers
;; reject the entire message otherwise.
(when (looking-at "^From[^:]")
(kill-region (point) (progn (forward-line) (point))))
;; turn into rfc822 format (\r\n eol's)
(while (search-forward "\n" nil t)
(replace-match "\r\n")))
- ;; this 'or' is for Cyrus server bug
- (or (null (imap-current-mailbox nnimap-server-buffer))
- (imap-mailbox-unselect nnimap-server-buffer))
+ ;; this 'or' is for Cyrus server bug
+ (or (null (imap-current-mailbox nnimap-server-buffer))
+ (imap-mailbox-unselect nnimap-server-buffer))
(imap-message-append group (current-buffer) nil nil
nnimap-server-buffer)))
(cons group (nth 1 uid))
(defun nnimap-expunge (mailbox server)
(when (nnimap-possibly-change-group mailbox server)
- (imap-mailbox-expunge nnimap-server-buffer)))
+ (imap-mailbox-expunge nil nnimap-server-buffer)))
(defun nnimap-acl-get (mailbox server)
(when (nnimap-possibly-change-server server)
(mapcar
(lambda (pair) ; cdr is the mark
(or (assoc (cdr pair)
- '((read . "SEEN")
- (tick . "FLAGGED")
- (draft . "DRAFT")
- (reply . "ANSWERED")))
- (cons (cdr pair)
- (format "KEYWORD gnus-%s" (symbol-name (cdr pair))))))
+ '((read . "SEEN")
+ (tick . "FLAGGED")
+ (draft . "DRAFT")
+ (recent . "RECENT")
+ (reply . "ANSWERED")))
+ (cons (cdr pair)
+ (format "KEYWORD gnus-%s" (symbol-name (cdr pair))))))
(cons '(read . read) gnus-article-mark-lists)))
(defun nnimap-mark-to-predicate (pred)
(mapcar
(lambda (pair)
(or (assoc (cdr pair)
- '((read . "\\Seen")
- (tick . "\\Flagged")
- (draft . "\\Draft")
- (reply . "\\Answered")))
- (cons (cdr pair)
- (format "gnus-%s" (symbol-name (cdr pair))))))
+ '((read . "\\Seen")
+ (tick . "\\Flagged")
+ (draft . "\\Draft")
+ (recent . "\\Recent")
+ (reply . "\\Answered")))
+ (cons (cdr pair)
+ (format "gnus-%s" (symbol-name (cdr pair))))))
(cons '(read . read) gnus-article-mark-lists)))
(defun nnimap-mark-to-flag-1 (preds)
"Return t iff MARK can be permanently (between IMAP sessions) saved on articles, in GROUP."
(imap-message-flag-permanent-p (nnimap-mark-to-flag mark)))
-(defun nnimap-remassoc (key alist)
- "Delete by side effect any elements of LIST whose car is `equal' to KEY.
-The modified LIST is returned. If the first member
-of LIST has a car that is `equal' to KEY, there is no way to remove it
-by side effect; therefore, write `(setq foo (remassoc key foo))' to be
-sure of changing the value of `foo'."
- (when alist
- (if (equal key (caar alist))
- (cdr alist)
- (setcdr alist (nnimap-remassoc key (cdr alist)))
- alist)))
-
-(defun nnimap-update-alist-soft (key value alist)
- (if value
- (cons (cons key value) (nnimap-remassoc key alist))
- (nnimap-remassoc key alist)))
-
(when nnimap-debug
(require 'trace)
(buffer-disable-undo (get-buffer-create nnimap-debug))
(mapcar (lambda (f) (trace-function-background f nnimap-debug))
- '(
- nnimap-possibly-change-server
- nnimap-verify-uidvalidity
- nnimap-find-minmax-uid
- nnimap-before-find-minmax-bugworkaround
- nnimap-possibly-change-group
- ;;nnimap-replace-whitespace
- nnimap-retrieve-headers-progress
- nnimap-retrieve-which-headers
- nnimap-group-overview-filename
- nnimap-retrieve-headers-from-file
- nnimap-retrieve-headers-from-server
- nnimap-retrieve-headers
- nnimap-open-connection
- nnimap-open-server
- nnimap-server-opened
- nnimap-close-server
- nnimap-request-close
- nnimap-status-message
- ;;nnimap-demule
- nnimap-request-article-part
- nnimap-request-article
- nnimap-request-head
- nnimap-request-body
- nnimap-request-group
- nnimap-close-group
- nnimap-pattern-to-list-arguments
- nnimap-request-list
- nnimap-request-post
- nnimap-retrieve-groups
- nnimap-request-update-info-internal
- nnimap-request-type
- nnimap-request-set-mark
- nnimap-split-to-groups
- nnimap-split-find-rule
- nnimap-split-find-inbox
- nnimap-split-articles
- nnimap-request-scan
- nnimap-request-newgroups
- nnimap-request-create-group
- nnimap-time-substract
- nnimap-date-days-ago
- nnimap-request-expire-articles-progress
- nnimap-request-expire-articles
- nnimap-request-move-article
- nnimap-request-accept-article
- nnimap-request-delete-group
- nnimap-request-rename-group
- gnus-group-nnimap-expunge
- gnus-group-nnimap-edit-acl
- gnus-group-nnimap-edit-acl-done
- nnimap-group-mode-hook
- nnimap-mark-to-predicate
- nnimap-mark-to-flag-1
- nnimap-mark-to-flag
- nnimap-mark-permanent-p
- nnimap-remassoc
- nnimap-update-alist-soft
- )))
+ '(
+ nnimap-possibly-change-server
+ nnimap-verify-uidvalidity
+ nnimap-find-minmax-uid
+ nnimap-before-find-minmax-bugworkaround
+ nnimap-possibly-change-group
+ ;;nnimap-replace-whitespace
+ nnimap-retrieve-headers-progress
+ nnimap-retrieve-which-headers
+ nnimap-group-overview-filename
+ nnimap-retrieve-headers-from-file
+ nnimap-retrieve-headers-from-server
+ nnimap-retrieve-headers
+ nnimap-open-connection
+ nnimap-open-server
+ nnimap-server-opened
+ nnimap-close-server
+ nnimap-request-close
+ nnimap-status-message
+ ;;nnimap-demule
+ nnimap-request-article-part
+ nnimap-request-article
+ nnimap-request-head
+ nnimap-request-body
+ nnimap-request-group
+ nnimap-close-group
+ nnimap-pattern-to-list-arguments
+ nnimap-request-list
+ nnimap-request-post
+ nnimap-retrieve-groups
+ nnimap-request-update-info-internal
+ nnimap-request-type
+ nnimap-request-set-mark
+ nnimap-split-to-groups
+ nnimap-split-find-rule
+ nnimap-split-find-inbox
+ nnimap-split-articles
+ nnimap-request-scan
+ nnimap-request-newgroups
+ nnimap-request-create-group
+ nnimap-time-substract
+ nnimap-date-days-ago
+ nnimap-request-expire-articles-progress
+ nnimap-request-expire-articles
+ nnimap-request-move-article
+ nnimap-request-accept-article
+ nnimap-request-delete-group
+ nnimap-request-rename-group
+ gnus-group-nnimap-expunge
+ gnus-group-nnimap-edit-acl
+ gnus-group-nnimap-edit-acl-done
+ nnimap-group-mode-hook
+ nnimap-mark-to-predicate
+ nnimap-mark-to-flag-1
+ nnimap-mark-to-flag
+ nnimap-mark-permanent-p
+ )))
(provide 'nnimap)
nnkiboze-remove-read-articles)
(let ((coding-system-for-write nnkiboze-file-coding-system))
(with-temp-file (nnkiboze-nov-file-name)
- (let ((cur (current-buffer))
+ (let ((cur (current-buffer))
(nnheader-file-coding-system nnkiboze-file-coding-system))
(nnheader-insert-file-contents (nnkiboze-nov-file-name))
(goto-char (point-min))
(defun nnkiboze-generate-group (group &optional inhibit-list-groups)
(let* ((info (nth 2 (gnus-gethash group gnus-newsrc-hashtb)))
(newsrc-file (concat nnkiboze-directory
- (nnheader-translate-file-chars
- (concat group ".newsrc"))))
+ (nnheader-translate-file-chars
+ (concat group ".newsrc"))))
(nov-file (concat nnkiboze-directory
- (nnheader-translate-file-chars
- (concat group ".nov"))))
+ (nnheader-translate-file-chars
+ (concat group ".nov"))))
method nnkiboze-newsrc gname newsrc active
ginfo lowest glevel orig-info nov-buffer
;; Bind various things to nil to make group entry faster.
(gnus-score-use-all-scores nil)
(gnus-use-scoring t)
(gnus-verbose (min gnus-verbose 3))
- gnus-select-group-hook gnus-summary-prepare-hook
+ gnus-select-group-hook gnus-summary-prepare-hook
gnus-thread-sort-functions gnus-show-threads
gnus-visual gnus-suppress-duplicates num-unread)
(unless info
(when (file-exists-p nov-file)
(insert-file-contents nov-file))
(setq nov-buffer (current-buffer))
- ;; Go through the active hashtb and add new all groups that match the
+ ;; Go through the active hashtb and add new all groups that match the
;; kiboze regexp.
(mapatoms
(lambda (group)
(and (string-match nnkiboze-regexp
- (setq gname (symbol-name group))) ; Match
+ (setq gname (symbol-name group))) ; Match
(not (assoc gname nnkiboze-newsrc)) ; It isn't registered
(numberp (car (symbol-value group))) ; It is active
(or (> nnkiboze-level 7)
(and (setq glevel (nth 1 (nth 2 (gnus-gethash
gname gnus-newsrc-hashtb))))
(>= nnkiboze-level glevel)))
- (not (string-match "^nnkiboze:" gname)) ; Exclude kibozes
+ (not (string-match "^nnkiboze:" gname)) ; Exclude kibozes
(push (cons gname (1- (car (symbol-value group))))
nnkiboze-newsrc)))
gnus-active-hashtb)
;; `newsrc' is set to the list of groups that possibly are
- ;; component groups to this kiboze group. This list has elements
+ ;; component groups to this kiboze group. This list has elements
;; on the form `(GROUP . NUMBER)', where NUMBER is the highest
;; number that has been kibozed in GROUP in this kiboze group.
(setq newsrc nnkiboze-newsrc)
(while newsrc
(if (not (setq active (gnus-gethash
(caar newsrc) gnus-active-hashtb)))
- ;; This group isn't active after all, so we remove it from
+ ;; This group isn't active after all, so we remove it from
;; the list of component groups.
(setq nnkiboze-newsrc (delq (car newsrc) nnkiboze-newsrc))
(setq lowest (cdar newsrc))
gnus-newsrc-hashtb)))
(unwind-protect
(progn
- ;; We set all list of article marks to nil. Since we operate
- ;; on copies of the real lists, we can destroy anything we
+ ;; We set all list of article marks to nil. Since we operate
+ ;; on copies of the real lists, we can destroy anything we
;; want here.
(when (nth 3 ginfo)
(setcar (nthcdr 3 ginfo) nil))
- ;; We set the list of read articles to be what we expect for
- ;; this kiboze group -- either nil or `(1 . LOWEST)'.
+ ;; We set the list of read articles to be what we expect for
+ ;; this kiboze group -- either nil or `(1 . LOWEST)'.
(when ginfo
(setcar (nthcdr 2 ginfo)
(and (not (= lowest 1)) (cons 1 lowest))))
;; We go through the list of scored articles.
(while gnus-newsgroup-scored
(when (> (caar gnus-newsgroup-scored) lowest)
- ;; If it has a good score, then we enter this article
+ ;; If it has a good score, then we enter this article
;; into the kiboze group.
(nnkiboze-enter-nov
nov-buffer
;;; Commentary:
-;; Note: You need to have `url' and `w3' installed for this
-;; backend to work.
-
;;; Code:
(eval-when-compile (require 'cl))
(require 'nnoo)
-(eval-when-compile
- (ignore-errors
- (require 'nnweb)) ; requires W3
- (autoload 'url-insert-file-contents "nnweb"))
+(require 'mm-url)
+(require 'nnweb)
(nnoo-declare nnlistserv
nnweb)
(when (funcall (nnweb-definition 'search) page)
;; Go through all the article hits on this page.
(goto-char (point-min))
- (nnweb-decode-entities)
+ (mm-url-decode-entities)
(goto-char (point-min))
(while (re-search-forward "^<li> *<a href=\"\\([^\"]+\\)\"><b>\\([^\\>]+\\)</b></a> *<[^>]+><i>\\([^>]+\\)<" nil t)
(setq url (match-string 1)
(let ((case-fold-search t)
(headers '(sent name email subject id))
sent name email subject id)
- (nnweb-decode-entities)
+ (mm-url-decode-entities)
(while headers
(goto-char (point-min))
(re-search-forward (format "<!-- %s=\"\\([^\"]+\\)" (car headers) nil t))
(goto-char (point-max))
(search-backward "<!-- body" nil t)
(delete-region (point-max) (progn (beginning-of-line) (point)))
- (nnweb-remove-markup)
+ (mm-url-remove-markup)
(goto-char (point-min))
(insert (format "From: %s <%s>\n" name email)
(format "Subject: %s\n" subject)
(format "Date: %s\n\n" sent))))
(defun nnlistserv-kk-search (search)
- (url-insert-file-contents
+ (mm-url-insert
(concat (format (nnweb-definition 'address) search)
(nnweb-definition 'index)))
t)
(eval-and-compile
(autoload 'gnus-error "gnus-util")
- (autoload 'gnus-buffer-live-p "gnus-util"))
+ (autoload 'gnus-buffer-live-p "gnus-util")
+ (autoload 'gnus-add-buffer "gnus"))
(defgroup nnmail nil
"Reading mail with Gnus."
"Various mail options."
:group 'nnmail)
-(defcustom nnmail-split-methods
- '(("mail.misc" ""))
+(defcustom nnmail-split-methods '(("mail.misc" ""))
"*Incoming mail will be split according to this variable.
If you'd like, for instance, one mail group for mail from the
(setq nnmail-split-methods
'((\"mail.4ad\" \"From:.*4ad\")
- (\"mail.junk\" \"From:.*Lars\\\\|Subject:.*buy\")
- (\"mail.misc\" \"\")))
+ (\"mail.junk\" \"From:.*Lars\\\\|Subject:.*buy\")
+ (\"mail.misc\" \"\")))
As you can see, this variable is a list of lists, where the first
element in each \"rule\" is the name of the group (which, by the way,
:group 'nnmail-split
:type 'boolean)
+(defcustom nnmail-split-fancy-with-parent-ignore-groups nil
+ "Regexp that matches group names to be ignored when applying
+`nnmail-split-fancy-with-parent'. This can also be a list of regexps."
+ :group 'nnmail-split
+ :type '(choice (const :tag "none" nil)
+ (regexp :value ".*")
+ (repeat :value (".*") regexp)))
+
;; Added by gord@enci.ucalgary.ca (Gordon Matzigkeit).
(defcustom nnmail-keep-last-article nil
"If non-nil, nnmail will never delete/move a group's last article.
\(setq nnmail-expiry-wait-function
(lambda (newsgroup)
- (cond ((string-match \"private\" newsgroup) 31)
- ((string-match \"junk\" newsgroup) 1)
+ (cond ((string-match \"private\" newsgroup) 31)
+ ((string-match \"junk\" newsgroup) 1)
((string-match \"important\" newsgroup) 'never)
(t 7))))"
:group 'nnmail-expire
receives one argument, the name of the group the message comes from.
The return value should be `delete' or a group name (a string)."
:version "21.1"
- :group 'nnmail-expire
- :type '(choice (const delete)
- (function :format "%v" nnmail-)
- string))
+ :group 'nnmail-expire
+ :type '(choice (const delete)
+ (function :format "%v" nnmail-)
+ string))
+
+(defcustom nnmail-fancy-expiry-targets nil
+ "Determine expiry target based on articles using fancy techniques.
+
+This is a list of (\"HEADER\" \"REGEXP\" \"TARGET\") entries. If
+`nnmail-expiry-target' is set to the function
+`nnmail-fancy-expiry-target' and HEADER of the article matches REGEXP,
+the message will be expired to a group determined by invoking
+`format-time-string' with TARGET used as the format string and the
+time extracted from the articles' Date header (if missing the current
+time is used).
+
+In the special cases that HEADER is the symbol `to-from', the regexp
+will try to match against both the From and the To header.
+
+Example:
+
+\(setq nnmail-fancy-expiry-targets
+ '((to-from \"boss\" \"nnfolder:Work\")
+ (\"Subject\" \"IMPORTANT\" \"nnfolder:IMPORTANT.%Y.%b\")
+ (\"from\" \".*\" \"nnfolder:Archive-%Y\")))
+
+In this case, articles containing the string \"boss\" in the To or the
+From header will be expired to the group \"nnfolder:Work\";
+articles containing the sting \"IMPORTANT\" in the Subject header will
+be expired to the group \"nnfolder:IMPORTANT.YYYY.MMM\"; and
+everything else will be expired to \"nnfolder:Archive-YYYY\"."
+ :group 'nnmail-expire
+ :type '(repeat (list (choice :tag "Match against"
+ (string :tag "Header")
+ (const to-from))
+ regexp
+ (string :tag "Target group format string"))))
(defcustom nnmail-cache-accepted-message-ids nil
"If non-nil, put Message-IDs of Gcc'd articles into the duplicate cache.
Eg.
\(add-hook 'nnmail-read-incoming-hook
- (lambda ()
- (call-process \"/local/bin/mailsend\" nil nil nil
- \"read\" nnmail-spool-file)))
+ (lambda ()
+ (call-process \"/local/bin/mailsend\" nil nil nil
+ \"read\" nnmail-spool-file)))
If you have xwatch running, this will alert it that mail has been
read.
\(FIELD VALUE [- RESTRICT [- RESTRICT [...]]] SPLIT): If the message
field FIELD (a regexp) contains VALUE (a regexp), store the messages
as specified by SPLIT. If RESTRICT (a regexp) matches some string
- after FIELD and before the end of the matched VALUE, return NIL,
+ after FIELD and before the end of the matched VALUE, return nil,
otherwise process SPLIT. Multiple RESTRICTs add up, further
restricting the possibility of processing SPLIT.
return value FUNCTION should be a split, which is then recursively
processed.
+junk: Mail will be deleted. Use with care! Do not submerge in water!
+ Example:
+ (setq nnmail-split-fancy
+ '(| (\"Subject\" \"MAKE MONEY FAST\" junk)
+ ...other.rules.omitted...))
+
FIELD must match a complete field name. VALUE must match a complete
word according to the `nnmail-split-fancy-syntax-table' syntax table.
You can use \".*\" in the regexps to match partial field names or words.
;; Other mailing lists...
(any \"procmail@informatik\\\\.rwth-aachen\\\\.de\" \"procmail.list\")
(any \"SmartList@informatik\\\\.rwth-aachen\\\\.de\" \"SmartList.list\")
- ;; Both lists below have the same suffix, so prevent
- ;; cross-posting to mkpkg.list of messages posted only to
- ;; the bugs- list, but allow cross-posting when the
- ;; message was really cross-posted.
- (any \"bugs-mypackage@somewhere\" \"mypkg.bugs\")
- (any \"mypackage@somewhere\" - \"bugs-mypackage\" \"mypkg.list\")
- ;;
+ ;; Both lists below have the same suffix, so prevent
+ ;; cross-posting to mkpkg.list of messages posted only to
+ ;; the bugs- list, but allow cross-posting when the
+ ;; message was really cross-posted.
+ (any \"bugs-mypackage@somewhere\" \"mypkg.bugs\")
+ (any \"mypackage@somewhere\" - \"bugs-mypackage\" \"mypkg.list\")
+ ;;
;; People...
(any \"larsi@ifi\\\\.uio\\\\.no\" \"people.Lars Magne Ingebrigtsen\"))
;; Unmatched mail goes to the catch all group.
;;; Internal variables.
+(defvar nnmail-article-buffer " *nnmail incoming*"
+ "The buffer used for splitting incoming mails.")
+
(defvar nnmail-split-history nil
"List of group/article elements that say where the previous split put messages.")
mm-text-coding-system
"Coding system used in reading inbox")
-(defvar nnmail-pathname-coding-system 'iso-8859-1
+(defvar nnmail-pathname-coding-system nil
"*Coding system for pathname.")
(defun nnmail-find-file (file)
(set-buffer nntp-server-buffer)
(delete-region (point-min) (point-max))
(let ((format-alist nil)
- (after-insert-file-functions nil))
+ (after-insert-file-functions nil))
(condition-case ()
(let ((coding-system-for-read nnmail-file-coding-system)
(auto-mode-alist (mm-auto-mode-alist))
(setq group (read buffer))
(unless (stringp group)
(setq group (symbol-name group)))
- (if (and (numberp (setq max (read nntp-server-buffer)))
- (numberp (setq min (read nntp-server-buffer))))
+ (if (and (numberp (setq max (read buffer)))
+ (numberp (setq min (read buffer))))
(push (list group (cons min max))
group-assoc)))
(error nil))
start
(if (search-forward "\n\n" nil t)
(1- (point))
- ;; This will never happen, but just to be on the safe side --
- ;; if there is no head-body delimiter, we search a bit manually.
+ ;; This will never happen, but just to be on the safe side --
+ ;; if there is no head-body delimiter, we search a bit manually.
(while (and (looking-at "From \\|[^ \t]+:")
(not (eobp)))
(forward-line 1))
(goto-char (point-max))
(widen)
(setq head-end (point))
- ;; We try the Content-Length value. The idea: skip over the header
- ;; separator, then check what happens content-length bytes into the
- ;; message body. This should be either the end ot the buffer, the
- ;; message separator or a blank line followed by the separator.
- ;; The blank line should probably be deleted. If neither of the
- ;; three is met, the content-length header is probably invalid.
+ ;; We try the Content-Length value. The idea: skip over the header
+ ;; separator, then check what happens content-length bytes into the
+ ;; message body. This should be either the end ot the buffer, the
+ ;; message separator or a blank line followed by the separator.
+ ;; The blank line should probably be deleted. If neither of the
+ ;; three is met, the content-length header is probably invalid.
(when content-length
(forward-line 1)
(setq skip (+ (point) content-length))
start
(if (search-forward "\n\n" nil t)
(1- (point))
- ;; This will never happen, but just to be on the safe side --
- ;; if there is no head-body delimiter, we search a bit manually.
+ ;; This will never happen, but just to be on the safe side --
+ ;; if there is no head-body delimiter, we search a bit manually.
(while (and (looking-at "From \\|[^ \t]+:")
(not (eobp)))
(forward-line 1))
(if (search-forward "\n\n" nil t)
(1- (point))
;; This will never happen, but just to be on the safe side --
- ;; if there is no head-body delimiter, we search a bit manually.
+ ;; if there is no head-body delimiter, we search a bit manually.
(while (and (looking-at "From \\|[^ \t]+:")
(not (eobp)))
(forward-line 1))
group artnum-func)
"Go through the entire INCOMING file and pick out each individual mail.
FUNC will be called with the buffer narrowed to each mail."
- (let (;; If this is a group-specific split, we bind the split
+ (let ( ;; If this is a group-specific split, we bind the split
;; methods to just this group.
(nnmail-split-methods (if (and group
(not nnmail-resplit-incoming))
nnmail-split-methods)))
(save-excursion
;; Insert the incoming file.
- (set-buffer (get-buffer-create " *nnmail incoming*"))
+ (set-buffer (get-buffer-create nnmail-article-buffer))
(erase-buffer)
(let ((coding-system-for-read nnmail-incoming-coding-system))
(mm-insert-file-contents incoming))
(defun nnmail-article-group (func &optional trace)
"Look at the headers and return an alist of groups that match.
FUNC will be called with the group name to determine the article number."
- (let ((methods nnmail-split-methods)
+ (let ((methods (or nnmail-split-methods '(("bogus" ""))))
(obuf (current-buffer))
(beg (point-min))
end group-art method grp)
(defun nnmail-remove-list-identifiers ()
"Remove list identifiers from Subject headers."
- (let ((regexp
- (if (consp nnmail-list-identifiers)
+ (let ((regexp
+ (if (consp nnmail-list-identifiers)
(mapconcat 'identity nnmail-list-identifiers " *\\|")
nnmail-list-identifiers)))
(when regexp
(goto-char (point-min))
(while (re-search-forward
- (concat "^Subject: +\\(R[Ee]: +\\)*\\(" regexp " *\\)")
- nil t)
- (delete-region (match-beginning 2) (match-end 0))
- (beginning-of-line))
+ (concat "^Subject: +\\(R[Ee]: +\\)*\\(" regexp " *\\)")
+ nil t)
+ (delete-region (match-beginning 2) (match-end 0))
+ (beginning-of-line))
(when (re-search-forward "^Subject: +\\(\\(R[Ee]: +\\)+\\)R[Ee]: +" nil t)
- (delete-region (match-beginning 1) (match-end 1))
+ (delete-region (match-beginning 1) (match-end 1))
(beginning-of-line)))))
(defun nnmail-remove-tabs ()
(beginning-of-line)
(insert "X-Gnus-Broken-Eudora-"))
(goto-char (point-min))
- (when (re-search-forward "^In-Reply-To:[^\n]+\\(\n[ \t]+\\)" nil t)
- (replace-match "" t t nil 1))))
+ (when (re-search-forward "^\\(In-Reply-To:[^\n]+\\)\n[ \t]+" nil t)
+ (replace-match "\\1" t))))
(custom-add-option 'nnmail-prepare-incoming-header-hook
'nnmail-fix-eudora-headers)
;;; Utility functions
+(defun nnmail-do-request-post (accept-func &optional server)
+ "Utility function to directly post a message to an nnmail-derived group.
+Calls ACCEPT-FUNC (which should be `nnchoke-request-accept-article')
+to actually put the message in the right group."
+ (let ((success t))
+ (dolist (mbx (message-unquote-tokens
+ (message-tokenize-header
+ (message-fetch-field "Newsgroups") ", ")) success)
+ (let ((to-newsgroup (gnus-group-prefixed-name mbx gnus-command-method)))
+ (or (gnus-active to-newsgroup)
+ (gnus-activate-group to-newsgroup)
+ (if (gnus-y-or-n-p (format "No such group: %s. Create it? "
+ to-newsgroup))
+ (or (and (gnus-request-create-group
+ to-newsgroup gnus-command-method)
+ (gnus-activate-group to-newsgroup nil nil
+ gnus-command-method))
+ (error "Couldn't create group %s" to-newsgroup)))
+ (error "No such group: %s" to-newsgroup))
+ (unless (funcall accept-func mbx (nth 1 gnus-command-method))
+ (setq success nil))))))
+
(defun nnmail-split-fancy ()
"Fancy splitting method.
See the documentation for the variable `nnmail-split-fancy' for documentation."
(push (cdr cached-pair) nnmail-split-trace))
(let ((split-rest (cddr split))
(end (match-end 0))
- ;; The searched regexp is \(\(FIELD\).*\)\(VALUE\). So,
+ ;; The searched regexp is \(\(FIELD\).*\)\(VALUE\). So,
;; start-of-value is the the point just before the
- ;; beginning of the value, whereas after-header-name is
+ ;; beginning of the value, whereas after-header-name is
;; the point just after the field name.
(start-of-value (match-end 1))
(after-header-name (match-end 2)))
(let ((value (nth 1 split)))
(if (symbolp value)
(setq value (cdr (assq value nnmail-split-abbrev-alist))))
- ;; Someone might want to do a \N sub on this match, so get the
+ ;; Someone might want to do a \N sub on this match, so get the
;; correct match positions.
(re-search-backward value start-of-value))
(dolist (sp (nnmail-split-it (car split-rest)))
(or partial-rear "\\>")))
(push (cons split regexp) nnmail-split-cache)
;; Now that it's in the cache, just call nnmail-split-it again
- ;; on the same split, which will find it immediately in the cache.
+ ;; on the same split, which will find it immediately in the cache.
(nnmail-split-it split))))))
(defun nnmail-expand-newtext (newtext)
(set-buffer
(setq nnmail-cache-buffer
(get-buffer-create " *nnmail message-id cache*")))
+ (gnus-add-buffer)
(when (file-exists-p nnmail-message-id-cache-file)
(nnheader-insert-file-contents nnmail-message-id-cache-file))
(set-buffer-modified-p nil)
;; length of the list is equal to 1? -- kai
(let ((g nil))
(cond ((and (boundp 'group) group)
- (setq g group))
- ((and (boundp 'group-art-list) group-art-list
- (listp group-art-list))
- (setq g (caar group-art-list)))
- ((and (boundp 'group-art) group-art (listp group-art))
- (setq g (caar group-art)))
- (t (setq g "")))
+ (setq g group))
+ ((and (boundp 'group-art-list) group-art-list
+ (listp group-art-list))
+ (setq g (caar group-art-list)))
+ ((and (boundp 'group-art) group-art (listp group-art))
+ (setq g (caar group-art)))
+ (t (setq g "")))
(unless (gnus-buffer-live-p nnmail-cache-buffer)
- (nnmail-cache-open))
+ (nnmail-cache-open))
(save-excursion
- (set-buffer nnmail-cache-buffer)
- (goto-char (point-max))
- (if (and g (not (string= "" g))
- (gnus-methods-equal-p gnus-command-method
- (nnmail-cache-primary-mail-backend)))
- (insert id "\t" g "\n")
- (insert id "\n"))))))
+ (set-buffer nnmail-cache-buffer)
+ (goto-char (point-max))
+ (if (and g (not (string= "" g))
+ (gnus-methods-equal-p gnus-command-method
+ (nnmail-cache-primary-mail-backend)))
+ (insert id "\t" g "\n")
+ (insert id "\n"))))))
(defun nnmail-cache-primary-mail-backend ()
(let ((be-list (cons gnus-select-method gnus-secondary-select-methods))
- (be nil)
- (res nil))
+ (be nil)
+ (res nil))
(while (and (null res) be-list)
(setq be (car be-list))
(setq be-list (cdr be-list))
(when (and (gnus-method-option-p be 'respool)
- (eval (intern (format "%s-get-new-mail" (car be)))))
- (setq res be)))
+ (eval (intern (format "%s-get-new-mail" (car be)))))
+ (setq res be)))
res))
;; Fetch the group name corresponding to the message id stored in the
(set-buffer nnmail-cache-buffer)
(goto-char (point-max))
(when (search-backward id nil t)
- (beginning-of-line)
- (skip-chars-forward "^\n\r\t")
- (unless (eolp)
- (forward-char 1)
- (buffer-substring (point)
- (progn (end-of-line) (point))))))))
+ (beginning-of-line)
+ (skip-chars-forward "^\n\r\t")
+ (unless (eolp)
+ (forward-char 1)
+ (buffer-substring (point)
+ (progn (end-of-line) (point))))))))
;; Function for nnmail-split-fancy: look up all references in the
;; cache and if a match is found, return that group.
See the Info node `(gnus)Fancy Mail Splitting' for more details."
(let* ((refstr (or (message-fetch-field "references")
- (message-fetch-field "in-reply-to")))
- (references nil)
- (res nil))
+ (message-fetch-field "in-reply-to")))
+ (references nil)
+ (res nil)
+ (regexp (if (consp nnmail-split-fancy-with-parent-ignore-groups)
+ (mapconcat
+ (lambda (x) (format "\\(%s\\)" x))
+ nnmail-split-fancy-with-parent-ignore-groups
+ "\\|")
+ nnmail-split-fancy-with-parent-ignore-groups)))
(when refstr
(setq references (nreverse (gnus-split-references refstr)))
(unless (gnus-buffer-live-p nnmail-cache-buffer)
- (nnmail-cache-open))
+ (nnmail-cache-open))
(mapcar (lambda (x)
- (setq res (or (nnmail-cache-fetch-group x) res))
- (when (string= "drafts" res)
- (setq res nil)))
- references)
+ (setq res (or (nnmail-cache-fetch-group x) res))
+ (when (or (string= "drafts" res)
+ (and regexp res (string-match regexp res)))
+ (setq res nil)))
+ references)
res)))
(defun nnmail-cache-id-exists-p (id)
(setq source (append source
(list
:predicate
- `(lambda (file)
- (string-equal
- ,(concat group suffix)
- (file-name-nondirectory file))))))))
+ (gnus-byte-compile
+ `(lambda (file)
+ (string-equal
+ ,(concat group suffix)
+ (file-name-nondirectory file)))))))))
(when nnmail-fetched-sources
(if (member source nnmail-fetched-sources)
(setq source nil)
(when (setq new
(mail-source-fetch
source
- `(lambda (file orig-file)
- (nnmail-split-incoming
- file ',(intern (format "%s-save-mail" method))
- ',spool-func
- (if (equal file orig-file)
- nil
- (nnmail-get-split-group orig-file ',source))
- ',(intern (format "%s-active-number" method))))))
+ (gnus-byte-compile
+ `(lambda (file orig-file)
+ (nnmail-split-incoming
+ file ',(intern (format "%s-save-mail" method))
+ ',spool-func
+ (if (equal file orig-file)
+ nil
+ (nnmail-get-split-group orig-file ',source))
+ ',(intern (format "%s-active-number" method)))))))
(incf total new)
(incf i)))
;; If we did indeed read any incoming spools, we save all info.
;; We expire all articles on sight.
t)
((equal time '(0 0))
- ;; This is an ange-ftp group, and we don't have any dates.
+ ;; This is an ange-ftp group, and we don't have any dates.
nil)
((numberp days)
(setq days (days-to-time days))
(ignore-errors (time-less-p days (time-since time))))))))
(defun nnmail-expiry-target-group (target group)
+ ;; Do not invoke this from nntp-server-buffer! At least nnfolder clears
+ ;; that buffer if the nnfolder group isn't selected.
(let (nnmail-cache-accepted-message-ids)
;; Don't enter Message-IDs into cache.
;; Let users hack it in TARGET function.
(unless (eq target 'delete)
(gnus-request-accept-article target nil nil t))))
+(defun nnmail-fancy-expiry-target (group)
+ "Returns a target expiry group determined by `nnmail-fancy-expiry-targets'."
+ (let* (header
+ (case-fold-search nil)
+ (from (or (message-fetch-field "from") ""))
+ (to (or (message-fetch-field "to") ""))
+ (date (date-to-time
+ (or (message-fetch-field "date") (current-time-string))))
+ (target 'delete))
+ (dolist (regexp-target-pair (reverse nnmail-fancy-expiry-targets) target)
+ (setq header (car regexp-target-pair))
+ (cond
+ ;; If the header is to-from then match against the
+ ;; To or From header
+ ((and (equal header 'to-from)
+ (or (string-match (cadr regexp-target-pair) from)
+ (and (string-match message-dont-reply-to-names from)
+ (string-match (cadr regexp-target-pair) to))))
+ (setq target (format-time-string (caddr regexp-target-pair) date)))
+ ((and (not (equal header 'to-from))
+ (string-match (cadr regexp-target-pair)
+ (message-fetch-field header)))
+ (setq target
+ (format-time-string (caddr regexp-target-pair) date)))))))
+
(defun nnmail-check-syntax ()
"Check (and modify) the syntax of the message in the current buffer."
(save-restriction
--- /dev/null
+;;; nnmaildir.el --- maildir backend for Gnus
+;; Copyright (c) 2001 Free Software Foundation, Inc.
+;; Copyright (c) 2000, 2001 Paul Jarc <prj@po.cwru.edu>
+
+;; Author: Paul Jarc <prj@po.cwru.edu>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; Maildir format is documented in the maildir(5) man page from qmail
+;; and at <URL:http://cr.yp.to/proto/maildir.html>. nnmaildir also
+;; stores extra information in the .nnmaildir/ directory within a
+;; maildir.
+;;
+;; Some goals of nnmaildir:
+;; * Everything Just Works, and correctly. E.g., stale NOV data is
+;; ignored when articles have been edited; no need for
+;; -generate-nov-databases.
+;; * Perfect reliability: [C-g] will never corrupt its data in memory,
+;; and SIGKILL will never corrupt its data in the filesystem.
+;; * We make it easy to manipulate marks, etc., from outside Gnus.
+;; * All information about a group is stored in the maildir, for easy
+;; backup and restoring.
+;; * We use the filesystem as a database.
+;;
+;; Todo:
+;; * Ignore old NOV data when gnus-extra-headers has changed.
+;; * Don't force article renumbering, so nnmaildir can be used with
+;; the cache and agent. Alternatively, completely rewrite the Gnus
+;; backend interface, which would have other advantages.
+;;
+;; See also <URL:http://multivac.cwru.edu./nnmaildir/> until that
+;; information is added to the Gnus manual.
+
+;;; Code:
+
+(eval-and-compile
+ (require 'nnheader)
+ (require 'gnus)
+ (require 'gnus-util)
+ (require 'gnus-range)
+ (require 'gnus-start)
+ (require 'gnus-int)
+ (require 'message))
+(eval-when-compile
+ (require 'cl)
+ (require 'nnmail))
+
+(defconst nnmaildir-version "Gnus")
+
+(defvar nnmaildir-article-file-name nil
+ "*The filename of the most recently requested article. This variable is set
+by nnmaildir-request-article.")
+
+;; The filename of the article being moved/copied:
+(defvar nnmaildir--file nil)
+
+;; Variables to generate filenames of messages being delivered:
+(defvar nnmaildir--delivery-time "")
+(defconst nnmaildir--delivery-pid (number-to-string (emacs-pid)))
+(defvar nnmaildir--delivery-ct nil)
+
+;; An obarry containing symbols whose names are server names and whose values
+;; are servers:
+(defvar nnmaildir--servers (make-vector 3 0))
+;; A server which has not necessarily been added to nnmaildir--servers, or nil:
+(defvar nnmaildir--tmp-server nil)
+;; The current server:
+(defvar nnmaildir--cur-server nil)
+
+;; A server is a vector:
+["server-name"
+ select-method
+ "/expanded/path/to/directory/containing/symlinks/to/maildirs/"
+ directory-files-function
+ group-name-transformation-function
+ ;; An obarray containing symbols whose names are group names and whose values
+ ;; are groups:
+ group-hash
+ ;; A group which has not necessarily been added to the group hash, or nil:
+ tmp-group
+ current-group ;; or nil
+ "Last error message, or nil"
+ directory-modtime
+ get-new-mail-p ;; Should we split mail from mail-sources?
+ "new/group/creation/directory"]
+
+;; A group is a vector:
+["group.name"
+ "prefixed:group.name"
+ ;; Modification times of the "new", and "cur" directories:
+ new-modtime
+ cur-modtime
+ ;; A vector containing lists of articles:
+ [;; A list of articles, with article numbers in descending order, ending with
+ ;; article 1:
+ article-list
+ ;; An obarray containing symbols whose names are filename prefixes and whose
+ ;; values are articles:
+ file-hash
+ ;; Same as above, but keyed on Message-ID:
+ msgid-hash
+ ;; An article which has not necessarily been added to the file and msgid
+ ;; hashes, or nil:
+ tmp-article]
+ ;; A vector containing nil, or articles with NOV data:
+ nov-cache
+ ;; The index of the next nov-cache entry to be replaced:
+ nov-cache-index
+ ;; An obarray containing symbols whose names are mark names and whose values
+ ;; are modtimes of mark directories:
+ mark-modtime-hash]
+
+;; An article is a vector:
+["file.name.prefix"
+ ":2,suffix" ;; or 'expire if expired
+ number
+ "msgid"
+ ;; A NOV data vector, or nil:
+ ["subject\tfrom\tdate"
+ "references\tchars\lines"
+ "extra"
+ article-file-modtime]]
+
+(defmacro nnmaildir--srv-new () '(make-vector 11 nil))
+(defmacro nnmaildir--srv-get-name (server) `(aref ,server 0))
+(defmacro nnmaildir--srv-get-method (server) `(aref ,server 1))
+(defmacro nnmaildir--srv-get-dir (server) `(aref ,server 2))
+(defmacro nnmaildir--srv-get-ls (server) `(aref ,server 3))
+(defmacro nnmaildir--srv-get-groups (server) `(aref ,server 4))
+(defmacro nnmaildir--srv-get-tmpgrp (server) `(aref ,server 5))
+(defmacro nnmaildir--srv-get-curgrp (server) `(aref ,server 6))
+(defmacro nnmaildir--srv-get-error (server) `(aref ,server 7))
+(defmacro nnmaildir--srv-get-mtime (server) `(aref ,server 8))
+(defmacro nnmaildir--srv-get-gnm (server) `(aref ,server 9))
+(defmacro nnmaildir--srv-get-create-dir (server) `(aref ,server 10))
+(defmacro nnmaildir--srv-set-name (server val) `(aset ,server 0 ,val))
+(defmacro nnmaildir--srv-set-method (server val) `(aset ,server 1 ,val))
+(defmacro nnmaildir--srv-set-dir (server val) `(aset ,server 2 ,val))
+(defmacro nnmaildir--srv-set-ls (server val) `(aset ,server 3 ,val))
+(defmacro nnmaildir--srv-set-groups (server val) `(aset ,server 4 ,val))
+(defmacro nnmaildir--srv-set-tmpgrp (server val) `(aset ,server 5 ,val))
+(defmacro nnmaildir--srv-set-curgrp (server val) `(aset ,server 6 ,val))
+(defmacro nnmaildir--srv-set-error (server val) `(aset ,server 7 ,val))
+(defmacro nnmaildir--srv-set-mtime (server val) `(aset ,server 8 ,val))
+(defmacro nnmaildir--srv-set-gnm (server val) `(aset ,server 9 ,val))
+(defmacro nnmaildir--srv-set-create-dir (server val) `(aset ,server 10 ,val))
+
+(defmacro nnmaildir--grp-new () '(make-vector 8 nil))
+(defmacro nnmaildir--grp-get-name (group) `(aref ,group 0))
+(defmacro nnmaildir--grp-get-pname (group) `(aref ,group 1))
+(defmacro nnmaildir--grp-get-new (group) `(aref ,group 2))
+(defmacro nnmaildir--grp-get-cur (group) `(aref ,group 3))
+(defmacro nnmaildir--grp-get-lists (group) `(aref ,group 4))
+(defmacro nnmaildir--grp-get-cache (group) `(aref ,group 5))
+(defmacro nnmaildir--grp-get-index (group) `(aref ,group 6))
+(defmacro nnmaildir--grp-get-mmth (group) `(aref ,group 7))
+(defmacro nnmaildir--grp-set-name (group val) `(aset ,group 0 ,val))
+(defmacro nnmaildir--grp-set-pname (group val) `(aset ,group 1 ,val))
+(defmacro nnmaildir--grp-set-new (group val) `(aset ,group 2 ,val))
+(defmacro nnmaildir--grp-set-cur (group val) `(aset ,group 3 ,val))
+(defmacro nnmaildir--grp-set-lists (group val) `(aset ,group 4 ,val))
+(defmacro nnmaildir--grp-set-cache (group val) `(aset ,group 5 ,val))
+(defmacro nnmaildir--grp-set-index (group val) `(aset ,group 6 ,val))
+(defmacro nnmaildir--grp-set-mmth (group val) `(aset ,group 7 ,val))
+
+(defmacro nnmaildir--lists-new () '(make-vector 4 nil))
+(defmacro nnmaildir--lists-get-nlist (lists) `(aref ,lists 0))
+(defmacro nnmaildir--lists-get-flist (lists) `(aref ,lists 1))
+(defmacro nnmaildir--lists-get-mlist (lists) `(aref ,lists 2))
+(defmacro nnmaildir--lists-get-tmpart (lists) `(aref ,lists 3))
+(defmacro nnmaildir--lists-set-nlist (lists val) `(aset ,lists 0 ,val))
+(defmacro nnmaildir--lists-set-flist (lists val) `(aset ,lists 1 ,val))
+(defmacro nnmaildir--lists-set-mlist (lists val) `(aset ,lists 2 ,val))
+(defmacro nnmaildir--lists-set-tmpart (lists val) `(aset ,lists 3 ,val))
+
+(defmacro nnmaildir--nlist-last-num (list)
+ `(if ,list (nnmaildir--art-get-num (car ,list)) 0))
+(defmacro nnmaildir--nlist-art (list num)
+ `(and ,list
+ (>= (nnmaildir--art-get-num (car ,list)) ,num)
+ (nth (- (nnmaildir--art-get-num (car ,list)) ,num) ,list)))
+(defmacro nnmaildir--flist-art (list file)
+ `(symbol-value (intern-soft ,file ,list)))
+(defmacro nnmaildir--mlist-art (list msgid)
+ `(symbol-value (intern-soft ,msgid ,list)))
+
+(defmacro nnmaildir--art-new () '(make-vector 5 nil))
+(defmacro nnmaildir--art-get-prefix (article) `(aref ,article 0))
+(defmacro nnmaildir--art-get-suffix (article) `(aref ,article 1))
+(defmacro nnmaildir--art-get-num (article) `(aref ,article 2))
+(defmacro nnmaildir--art-get-msgid (article) `(aref ,article 3))
+(defmacro nnmaildir--art-get-nov (article) `(aref ,article 4))
+(defmacro nnmaildir--art-set-prefix (article val) `(aset ,article 0 ,val))
+(defmacro nnmaildir--art-set-suffix (article val) `(aset ,article 1 ,val))
+(defmacro nnmaildir--art-set-num (article val) `(aset ,article 2 ,val))
+(defmacro nnmaildir--art-set-msgid (article val) `(aset ,article 3 ,val))
+(defmacro nnmaildir--art-set-nov (article val) `(aset ,article 4 ,val))
+
+(defmacro nnmaildir--nov-new () '(make-vector 4 nil))
+(defmacro nnmaildir--nov-get-beg (nov) `(aref ,nov 0))
+(defmacro nnmaildir--nov-get-mid (nov) `(aref ,nov 1))
+(defmacro nnmaildir--nov-get-end (nov) `(aref ,nov 2))
+(defmacro nnmaildir--nov-get-mtime (nov) `(aref ,nov 3))
+(defmacro nnmaildir--nov-set-beg (nov val) `(aset ,nov 0 ,val))
+(defmacro nnmaildir--nov-set-mid (nov val) `(aset ,nov 1 ,val))
+(defmacro nnmaildir--nov-set-end (nov val) `(aset ,nov 2 ,val))
+(defmacro nnmaildir--nov-set-mtime (nov val) `(aset ,nov 3 ,val))
+
+(defmacro nnmaildir--srv-grp-dir (srv-dir gname)
+ `(file-name-as-directory (concat ,srv-dir ,gname)))
+
+(defun nnmaildir--param (prefixed-group-name param)
+ (setq param
+ (gnus-group-find-parameter prefixed-group-name param 'allow-list)
+ param (if (vectorp param) (aref param 0) param))
+ (eval param))
+
+(defmacro nnmaildir--unlink (file)
+ `(if (file-attributes ,file) (delete-file ,file)))
+
+(defmacro nnmaildir--tmp (dir) `(file-name-as-directory (concat ,dir "tmp")))
+(defmacro nnmaildir--new (dir) `(file-name-as-directory (concat ,dir "new")))
+(defmacro nnmaildir--cur (dir) `(file-name-as-directory (concat ,dir "cur")))
+(defmacro nnmaildir--nndir (dir)
+ `(file-name-as-directory (concat ,dir ".nnmaildir")))
+
+(defun nnmaildir--lists-fix (lists)
+ (let ((tmp (nnmaildir--lists-get-tmpart lists)))
+ (when tmp
+ (set (intern (nnmaildir--art-get-prefix tmp)
+ (nnmaildir--lists-get-flist lists))
+ tmp)
+ (set (intern (nnmaildir--art-get-msgid tmp)
+ (nnmaildir--lists-get-mlist lists))
+ tmp)
+ (nnmaildir--lists-set-tmpart lists nil))))
+
+(defun nnmaildir--prepare (server group)
+ (let (x groups)
+ (catch 'return
+ (setq x nnmaildir--tmp-server)
+ (when x
+ (set (intern (nnmaildir--srv-get-name x) nnmaildir--servers) x)
+ (setq nnmaildir--tmp-server nil))
+ (if (null server)
+ (or (setq server nnmaildir--cur-server)
+ (throw 'return nil))
+ (or (setq server (intern-soft server nnmaildir--servers))
+ (throw 'return nil))
+ (setq server (symbol-value server)
+ nnmaildir--cur-server server))
+ (setq groups (nnmaildir--srv-get-groups server))
+ (if groups nil (throw 'return nil))
+ (if (nnmaildir--srv-get-method server) nil
+ (setq x (concat "nnmaildir:" (nnmaildir--srv-get-name server))
+ x (gnus-server-to-method x))
+ (if x nil (throw 'return nil))
+ (nnmaildir--srv-set-method server x))
+ (setq x (nnmaildir--srv-get-tmpgrp server))
+ (when x
+ (set (intern (nnmaildir--grp-get-name x) groups) x)
+ (nnmaildir--srv-set-tmpgrp server nil))
+ (if (null group)
+ (or (setq group (nnmaildir--srv-get-curgrp server))
+ (throw 'return nil))
+ (setq group (intern-soft group groups))
+ (if group nil (throw 'return nil))
+ (setq group (symbol-value group)))
+ (nnmaildir--lists-fix (nnmaildir--grp-get-lists group))
+ group)))
+
+(defun nnmaildir--update-nov (srv-dir group article)
+ (let ((nnheader-file-coding-system 'binary)
+ dir gname pgname msgdir prefix suffix file attr mtime novdir novfile
+ nov msgid nov-beg nov-mid nov-end field pos extra val deactivate-mark)
+ (catch 'return
+ (setq suffix (nnmaildir--art-get-suffix article))
+ (if (stringp suffix) nil
+ (nnmaildir--art-set-nov article nil)
+ (throw 'return nil))
+ (setq gname (nnmaildir--grp-get-name group)
+ pgname (nnmaildir--grp-get-pname group)
+ dir (nnmaildir--srv-grp-dir srv-dir gname)
+ msgdir (if (nnmaildir--param pgname 'read-only)
+ (nnmaildir--new dir) (nnmaildir--cur dir))
+ prefix (nnmaildir--art-get-prefix article)
+ file (concat msgdir prefix suffix)
+ attr (file-attributes file))
+ (if attr nil
+ (nnmaildir--art-set-suffix article 'expire)
+ (nnmaildir--art-set-nov article nil)
+ (throw 'return nil))
+ (setq mtime (nth 5 attr)
+ attr (nth 7 attr)
+ nov (nnmaildir--art-get-nov article)
+ novdir (concat (nnmaildir--nndir dir) "nov")
+ novdir (file-name-as-directory novdir)
+ novfile (concat novdir prefix))
+ (save-excursion
+ (set-buffer (get-buffer-create " *nnmaildir nov*"))
+ (when (file-exists-p novfile)
+ (and nov
+ (equal mtime (nnmaildir--nov-get-mtime nov))
+ (throw 'return nov))
+ (erase-buffer)
+ (nnheader-insert-file-contents novfile)
+ (setq nov (read (current-buffer)))
+ (nnmaildir--art-set-msgid article (car nov))
+ (setq nov (cadr nov))
+ (and (equal mtime (nnmaildir--nov-get-mtime nov))
+ (throw 'return nov)))
+ (erase-buffer)
+ (nnheader-insert-file-contents file)
+ (insert "\n")
+ (goto-char (point-min))
+ (save-restriction
+ (if (search-forward "\n\n" nil 'noerror)
+ (progn
+ (setq nov-mid (count-lines (point) (point-max)))
+ (narrow-to-region (point-min) (1- (point))))
+ (setq nov-mid 0))
+ (goto-char (point-min))
+ (delete-char 1)
+ (nnheader-fold-continuation-lines)
+ (setq nov (nnheader-parse-head 'naked)
+ field (or (mail-header-lines nov) 0)))
+ (if (or (zerop field) (nnmaildir--param pgname 'distrust-Lines:)) nil
+ (setq nov-mid field))
+ (setq nov-mid (number-to-string nov-mid)
+ nov-mid (concat (number-to-string attr) "\t" nov-mid)
+ field (or (mail-header-references nov) "")
+ pos 0)
+ (save-match-data
+ (while (string-match "\t" field pos)
+ (aset field (match-beginning 0) ? )
+ (setq pos (match-end 0)))
+ (setq nov-mid (concat field "\t" nov-mid)
+ extra (mail-header-extra nov)
+ nov-end "")
+ (while extra
+ (setq field (car extra) extra (cdr extra)
+ val (cdr field) field (symbol-name (car field))
+ pos 0)
+ (while (string-match "\t" field pos)
+ (aset field (match-beginning 0) ? )
+ (setq pos (match-end 0)))
+ (setq pos 0)
+ (while (string-match "\t" val pos)
+ (aset val (match-beginning 0) ? )
+ (setq pos (match-end 0)))
+ (setq nov-end (concat nov-end "\t" field ": " val)))
+ (setq nov-end (if (zerop (length nov-end)) "" (substring nov-end 1))
+ field (or (mail-header-subject nov) "")
+ pos 0)
+ (while (string-match "\t" field pos)
+ (aset field (match-beginning 0) ? )
+ (setq pos (match-end 0)))
+ (setq nov-beg field
+ field (or (mail-header-from nov) "")
+ pos 0)
+ (while (string-match "\t" field pos)
+ (aset field (match-beginning 0) ? )
+ (setq pos (match-end 0)))
+ (setq nov-beg (concat nov-beg "\t" field)
+ field (or (mail-header-date nov) "")
+ pos 0)
+ (while (string-match "\t" field pos)
+ (aset field (match-beginning 0) ? )
+ (setq pos (match-end 0)))
+ (setq nov-beg (concat nov-beg "\t" field)
+ field (mail-header-id nov)
+ pos 0)
+ (while (string-match "\t" field pos)
+ (aset field (match-beginning 0) ? )
+ (setq pos (match-end 0)))
+ (setq msgid field))
+ (if (or (null msgid) (nnheader-fake-message-id-p msgid))
+ (setq msgid (concat "<" prefix "@nnmaildir>")))
+ (erase-buffer)
+ (setq nov (nnmaildir--nov-new))
+ (nnmaildir--nov-set-beg nov nov-beg)
+ (nnmaildir--nov-set-mid nov nov-mid)
+ (nnmaildir--nov-set-end nov nov-end)
+ (nnmaildir--nov-set-mtime nov mtime)
+ (prin1 (list msgid nov) (current-buffer))
+ (setq file (concat novdir ":"))
+ (nnmaildir--unlink file)
+ (write-region (point-min) (point-max) file nil 'no-message))
+ (rename-file file novfile 'replace)
+ (nnmaildir--art-set-msgid article msgid)
+ nov)))
+
+(defun nnmaildir--cache-nov (group article nov)
+ (let ((cache (nnmaildir--grp-get-cache group))
+ (index (nnmaildir--grp-get-index group))
+ goner)
+ (if (nnmaildir--art-get-nov article) nil
+ (setq goner (aref cache index))
+ (if goner (nnmaildir--art-set-nov goner nil))
+ (aset cache index article)
+ (nnmaildir--grp-set-index group (% (1+ index) (length cache))))
+ (nnmaildir--art-set-nov article nov)))
+
+(defun nnmaildir--grp-add-art (srv-dir group article)
+ (let ((nov (nnmaildir--update-nov srv-dir group article))
+ old-lists new-lists)
+ (when nov
+ (setq old-lists (nnmaildir--grp-get-lists group)
+ new-lists (nnmaildir--lists-new))
+ (nnmaildir--lists-set-nlist
+ new-lists (cons article (nnmaildir--lists-get-nlist old-lists)))
+ (nnmaildir--lists-set-flist new-lists
+ (nnmaildir--lists-get-flist old-lists))
+ (nnmaildir--lists-set-mlist new-lists
+ (nnmaildir--lists-get-mlist old-lists))
+ (nnmaildir--lists-set-tmpart new-lists article)
+ (nnmaildir--grp-set-lists group new-lists)
+ (nnmaildir--lists-fix new-lists)
+ (nnmaildir--cache-nov group article nov)
+ t)))
+
+(defun nnmaildir--mkdir (dir)
+ (or (file-exists-p (file-name-as-directory dir))
+ (make-directory-internal (directory-file-name dir))))
+
+(defun nnmaildir--article-count (group)
+ (let ((ct 0)
+ (min 0))
+ (setq group (nnmaildir--grp-get-lists group)
+ group (nnmaildir--lists-get-nlist group))
+ (while group
+ (if (stringp (nnmaildir--art-get-suffix (car group)))
+ (setq ct (1+ ct)
+ min (nnmaildir--art-get-num (car group))))
+ (setq group (cdr group)))
+ (cons ct min)))
+
+(defun nnmaildir-article-number-to-file-name
+ (number group-name server-address-string)
+ (let ((group (nnmaildir--prepare server-address-string group-name))
+ list article suffix dir filename)
+ (catch 'return
+ (if (null group)
+ ;; The given group or server does not exist.
+ (throw 'return nil))
+ (setq list (nnmaildir--grp-get-lists group)
+ list (nnmaildir--lists-get-nlist list)
+ article (nnmaildir--nlist-art list number))
+ (if (null article)
+ ;; The given article number does not exist in this group.
+ (throw 'return nil))
+ (setq suffix (nnmaildir--art-get-suffix article))
+ (if (not (stringp suffix))
+ ;; The article has expired.
+ (throw 'return nil))
+ (setq dir (nnmaildir--srv-get-dir nnmaildir--cur-server)
+ dir (nnmaildir--srv-grp-dir dir group-name)
+ group (if (nnmaildir--param (nnmaildir--grp-get-pname group)
+ 'read-only)
+ (nnmaildir--new dir) (nnmaildir--cur dir))
+ filename (concat group (nnmaildir--art-get-prefix article) suffix))
+ (if (file-exists-p filename)
+ filename
+ ;; The article disappeared out from under us.
+ (nnmaildir--art-set-suffix article 'expire)
+ (nnmaildir--art-set-nov article nil)
+ nil))))
+
+(defun nnmaildir-request-type (group &optional article)
+ 'mail)
+
+(defun nnmaildir-status-message (&optional server)
+ (nnmaildir--prepare server nil)
+ (nnmaildir--srv-get-error nnmaildir--cur-server))
+
+(defun nnmaildir-server-opened (&optional server)
+ (and nnmaildir--cur-server
+ (if server
+ (string-equal server
+ (nnmaildir--srv-get-name nnmaildir--cur-server))
+ t)
+ (nnmaildir--srv-get-groups nnmaildir--cur-server)
+ t))
+
+(defun nnmaildir-open-server (server &optional defs)
+ (let ((x server)
+ dir size)
+ (catch 'return
+ (setq server (intern-soft x nnmaildir--servers))
+ (if server
+ (and (setq server (symbol-value server))
+ (nnmaildir--srv-get-groups server)
+ (setq nnmaildir--cur-server server)
+ (throw 'return t))
+ (setq server (nnmaildir--srv-new))
+ (nnmaildir--srv-set-name server x)
+ (setq nnmaildir--tmp-server server)
+ (set (intern x nnmaildir--servers) server)
+ (setq nnmaildir--tmp-server nil))
+ (setq dir (assq 'directory defs))
+ (if dir nil
+ (nnmaildir--srv-set-error
+ server "You must set \"directory\" in the select method")
+ (throw 'return nil))
+ (setq dir (cadr dir)
+ dir (eval dir)
+ dir (expand-file-name dir)
+ dir (file-name-as-directory dir))
+ (if (file-exists-p dir) nil
+ (nnmaildir--srv-set-error server (concat "No such directory: " dir))
+ (throw 'return nil))
+ (nnmaildir--srv-set-dir server dir)
+ (setq x (assq 'directory-files defs))
+ (if (null x)
+ (setq x (symbol-function (if nnheader-directory-files-is-safe
+ 'directory-files
+ 'nnheader-directory-files-safe)))
+ (setq x (cadr x))
+ (if (functionp x) nil
+ (nnmaildir--srv-set-error
+ server (concat "Not a function: " (prin1-to-string x)))
+ (throw 'return nil)))
+ (nnmaildir--srv-set-ls server x)
+ (setq x (funcall x dir nil "\\`[^.]" 'nosort)
+ x (length x)
+ size 1)
+ (while (<= size x) (setq size (* 2 size)))
+ (if (/= size 1) (setq size (1- size)))
+ (and (setq x (assq 'get-new-mail defs))
+ (setq x (cdr x))
+ (car x)
+ (nnmaildir--srv-set-gnm server t)
+ (require 'nnmail))
+ (setq x (assq 'create-directory defs))
+ (when x
+ (setq x (cadr x)
+ x (eval x))
+ (nnmaildir--srv-set-create-dir server x))
+ (nnmaildir--srv-set-groups server (make-vector size 0))
+ (setq nnmaildir--cur-server server)
+ t)))
+
+(defun nnmaildir--parse-filename (file)
+ (let ((prefix (car file))
+ timestamp len)
+ (if (string-match
+ "\\`\\([0-9]+\\)\\.\\([0-9]+\\)\\(_\\([0-9]+\\)\\)?\\(\\..*\\)\\'"
+ prefix)
+ (progn
+ (setq timestamp (concat "0000" (match-string 1 prefix))
+ len (- (length timestamp) 4))
+ (vector (string-to-number (substring timestamp 0 len))
+ (string-to-number (substring timestamp len))
+ (string-to-number (match-string 2 prefix))
+ (string-to-number (or (match-string 4 prefix) "-1"))
+ (match-string 5 prefix)
+ file))
+ file)))
+
+(defun nnmaildir--sort-files (a b)
+ (catch 'return
+ (if (consp a)
+ (throw 'return (and (consp b) (string-lessp (car a) (car b)))))
+ (if (consp b) (throw 'return t))
+ (if (< (aref a 0) (aref b 0)) (throw 'return t))
+ (if (> (aref a 0) (aref b 0)) (throw 'return nil))
+ (if (< (aref a 1) (aref b 1)) (throw 'return t))
+ (if (> (aref a 1) (aref b 1)) (throw 'return nil))
+ (if (< (aref a 2) (aref b 2)) (throw 'return t))
+ (if (> (aref a 2) (aref b 2)) (throw 'return nil))
+ (if (< (aref a 3) (aref b 3)) (throw 'return t))
+ (if (> (aref a 3) (aref b 3)) (throw 'return nil))
+ (string-lessp (aref a 4) (aref b 4))))
+
+(defun nnmaildir--scan (gname scan-msgs groups method srv-dir srv-ls)
+ (catch 'return
+ (let ((36h-ago (- (car (current-time)) 2))
+ absdir nndir tdir ndir cdir nattr cattr isnew pgname read-only ls
+ files file num dir flist group x)
+ (setq absdir (file-name-as-directory (concat srv-dir gname))
+ nndir (nnmaildir--nndir absdir))
+ (if (file-attributes absdir) nil
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "No such directory: " absdir))
+ (throw 'return nil))
+ (setq tdir (nnmaildir--tmp absdir)
+ ndir (nnmaildir--new absdir)
+ cdir (nnmaildir--cur absdir)
+ nattr (file-attributes ndir)
+ cattr (file-attributes cdir))
+ (if (and (file-exists-p tdir) nattr cattr) nil
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "Not a maildir: " absdir))
+ (throw 'return nil))
+ (setq group (nnmaildir--prepare nil gname))
+ (if group
+ (setq isnew nil
+ pgname (nnmaildir--grp-get-pname group))
+ (setq isnew t
+ group (nnmaildir--grp-new)
+ pgname (gnus-group-prefixed-name gname method))
+ (nnmaildir--grp-set-name group gname)
+ (nnmaildir--grp-set-pname group pgname)
+ (nnmaildir--grp-set-lists group (nnmaildir--lists-new))
+ (nnmaildir--grp-set-index group 0)
+ (nnmaildir--mkdir nndir)
+ (nnmaildir--mkdir (concat nndir "nov"))
+ (nnmaildir--mkdir (concat nndir "marks"))
+ (write-region "" nil (concat nndir "markfile") nil 'no-message))
+ (setq read-only (nnmaildir--param pgname 'read-only)
+ ls (or (nnmaildir--param pgname 'directory-files) srv-ls))
+ (if read-only nil
+ (setq x (nth 11 (file-attributes tdir)))
+ (if (and (= x (nth 11 nattr)) (= x (nth 11 cattr))) nil
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "Maildir spans filesystems: "
+ absdir))
+ (throw 'return nil))
+ (setq files (funcall ls tdir 'full "\\`[^.]" 'nosort))
+ (while files
+ (setq file (car files) files (cdr files)
+ x (file-attributes file))
+ (if (or (< 1 (cadr x)) (> 36h-ago (car (nth 4 x))))
+ (delete-file file))))
+ (or scan-msgs
+ isnew
+ (throw 'return t))
+ (setq nattr (nth 5 nattr))
+ (if (equal nattr (nnmaildir--grp-get-new group))
+ (setq nattr nil))
+ (if read-only (setq dir (and (or isnew nattr) ndir))
+ (when (or isnew nattr)
+ (setq files (funcall ls ndir nil "\\`[^.]" 'nosort))
+ (while files
+ (setq file (car files) files (cdr files))
+ (rename-file (concat ndir file) (concat cdir file ":2,")))
+ (nnmaildir--grp-set-new group nattr))
+ (setq cattr (file-attributes cdir)
+ cattr (nth 5 cattr))
+ (if (equal cattr (nnmaildir--grp-get-cur group))
+ (setq cattr nil))
+ (setq dir (and (or isnew cattr) cdir)))
+ (if dir nil (throw 'return t))
+ (setq files (funcall ls dir nil "\\`[^.]" 'nosort))
+ (when isnew
+ (setq x (length files)
+ num 1)
+ (while (<= num x) (setq num (* 2 num)))
+ (if (/= num 1) (setq num (1- num)))
+ (setq x (nnmaildir--grp-get-lists group))
+ (nnmaildir--lists-set-flist x (make-vector num 0))
+ (nnmaildir--lists-set-mlist x (make-vector num 0))
+ (nnmaildir--grp-set-mmth group (make-vector 1 0))
+ (setq num (nnmaildir--param pgname 'nov-cache-size))
+ (if (numberp num) (if (< num 1) (setq num 1))
+ (setq x files
+ num 16
+ cdir (file-name-as-directory (concat nndir "marks"))
+ ndir (file-name-as-directory (concat cdir "tick"))
+ cdir (file-name-as-directory (concat cdir "read")))
+ (while x
+ (setq file (car x) x (cdr x))
+ (string-match "\\`\\([^:]*\\)\\(\\(:.*\\)?\\)\\'" file)
+ (setq file (match-string 1 file))
+ (if (or (not (file-exists-p (concat cdir file)))
+ (file-exists-p (concat ndir file)))
+ (setq num (1+ num)))))
+ (nnmaildir--grp-set-cache group (make-vector num nil))
+ (nnmaildir--srv-set-tmpgrp nnmaildir--cur-server group)
+ (set (intern gname groups) group)
+ (nnmaildir--srv-set-tmpgrp nnmaildir--cur-server nil)
+ (or scan-msgs (throw 'return t)))
+ (setq flist (nnmaildir--grp-get-lists group)
+ num (nnmaildir--lists-get-nlist flist)
+ flist (nnmaildir--lists-get-flist flist)
+ num (nnmaildir--nlist-last-num num)
+ x files
+ files nil)
+ (while x
+ (setq file (car x) x (cdr x))
+ (string-match "\\`\\([^:]*\\)\\(\\(:.*\\)?\\)\\'" file)
+ (setq file (cons (match-string 1 file) (match-string 2 file)))
+ (if (nnmaildir--flist-art flist (car file)) nil
+ (setq files (cons file files))))
+ (setq files (mapcar 'nnmaildir--parse-filename files)
+ files (sort files 'nnmaildir--sort-files))
+ (while files
+ (setq file (car files) files (cdr files)
+ file (if (consp file) file (aref file 5))
+ x (nnmaildir--art-new))
+ (nnmaildir--art-set-prefix x (car file))
+ (nnmaildir--art-set-suffix x (cdr file))
+ (nnmaildir--art-set-num x (1+ num))
+ (if (nnmaildir--grp-add-art srv-dir group x)
+ (setq num (1+ num))))
+ (if read-only (nnmaildir--grp-set-new group nattr)
+ (nnmaildir--grp-set-cur group cattr)))
+ t))
+
+(defun nnmaildir-request-scan (&optional scan-group server)
+ (let ((coding-system-for-write nnheader-file-coding-system)
+ (buffer-file-coding-system nil)
+ (file-coding-system-alist nil)
+ (nnmaildir-get-new-mail t)
+ (nnmaildir-group-alist nil)
+ (nnmaildir-active-file nil)
+ x srv-ls srv-dir method groups group dirs grp-dir seen deactivate-mark)
+ (nnmaildir--prepare server nil)
+ (setq srv-ls (nnmaildir--srv-get-ls nnmaildir--cur-server)
+ srv-dir (nnmaildir--srv-get-dir nnmaildir--cur-server)
+ method (nnmaildir--srv-get-method nnmaildir--cur-server)
+ groups (nnmaildir--srv-get-groups nnmaildir--cur-server))
+ (save-excursion
+ (set-buffer (get-buffer-create " *nnmaildir work*"))
+ (save-match-data
+ (if (stringp scan-group)
+ (if (nnmaildir--scan scan-group t groups method srv-dir srv-ls)
+ (if (nnmaildir--srv-get-gnm nnmaildir--cur-server)
+ (nnmail-get-new-mail 'nnmaildir nil nil scan-group))
+ (unintern scan-group groups))
+ (setq x (nth 5 (file-attributes srv-dir)))
+ (if (equal x (nnmaildir--srv-get-mtime nnmaildir--cur-server))
+ (if scan-group nil
+ (mapatoms (lambda (sym)
+ (nnmaildir--scan (symbol-name sym) t groups
+ method srv-dir srv-ls))
+ groups))
+ (setq dirs (funcall srv-ls srv-dir nil "\\`[^.]" 'nosort)
+ x (length dirs)
+ seen 1)
+ (while (<= seen x) (setq seen (* 2 seen)))
+ (if (/= seen 1) (setq seen (1- seen)))
+ (setq seen (make-vector seen 0)
+ scan-group (null scan-group))
+ (while dirs
+ (setq grp-dir (car dirs) dirs (cdr dirs))
+ (if (nnmaildir--scan grp-dir scan-group groups method srv-dir
+ srv-ls)
+ (intern grp-dir seen)))
+ (setq x nil)
+ (mapatoms (lambda (group)
+ (setq group (symbol-name group))
+ (if (intern-soft group seen) nil
+ (setq x (cons group x))))
+ groups)
+ (while x
+ (unintern (car x) groups)
+ (setq x (cdr x)))
+ (nnmaildir--srv-set-mtime nnmaildir--cur-server
+ (nth 5 (file-attributes srv-dir))))
+ (if (nnmaildir--srv-get-gnm nnmaildir--cur-server)
+ (nnmail-get-new-mail 'nnmaildir nil nil))))))
+ t)
+
+(defun nnmaildir-request-list (&optional server)
+ (nnmaildir-request-scan 'find-new-groups server)
+ (let (pgname ro ct-min deactivate-mark)
+ (nnmaildir--prepare server nil)
+ (save-excursion
+ (set-buffer nntp-server-buffer)
+ (erase-buffer)
+ (mapatoms (lambda (group)
+ (setq group (symbol-value group)
+ ro (nnmaildir--param (nnmaildir--grp-get-pname group)
+ 'read-only)
+ ct-min (nnmaildir--article-count group))
+ (insert (nnmaildir--grp-get-name group) " ")
+ (princ (car ct-min) nntp-server-buffer)
+ (insert " ")
+ (princ (cdr ct-min) nntp-server-buffer)
+ (insert " " (if ro "n" "y") "\n"))
+ (nnmaildir--srv-get-groups nnmaildir--cur-server))))
+ t)
+
+(defun nnmaildir-request-newgroups (date &optional server)
+ (nnmaildir-request-list server))
+
+(defun nnmaildir-retrieve-groups (groups &optional server)
+ (let (gname group ct-min deactivate-mark)
+ (nnmaildir--prepare server nil)
+ (save-excursion
+ (set-buffer nntp-server-buffer)
+ (erase-buffer)
+ (while groups
+ (setq gname (car groups) groups (cdr groups))
+ (nnmaildir-request-scan gname server)
+ (setq group (nnmaildir--prepare nil gname))
+ (if (null group) (insert "411 no such news group\n")
+ (setq ct-min (nnmaildir--article-count group))
+ (insert "211 ")
+ (princ (car ct-min) nntp-server-buffer)
+ (insert " ")
+ (princ (cdr ct-min) nntp-server-buffer)
+ (insert " ")
+ (princ (nnmaildir--nlist-last-num
+ (nnmaildir--lists-get-nlist
+ (nnmaildir--grp-get-lists group)))
+ nntp-server-buffer)
+ (insert " " gname "\n")))))
+ 'group)
+
+(defun nnmaildir-request-update-info (gname info &optional server)
+ (nnmaildir-request-scan gname server)
+ (let ((group (nnmaildir--prepare server gname))
+ srv-ls pgname nlist flist last always-marks never-marks old-marks
+ dotfile num dir markdirs marks mark ranges articles article read end
+ new-marks ls old-mmth new-mmth mtime mark-sym deactivate-mark)
+ (catch 'return
+ (if group nil
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "No such group: " gname))
+ (throw 'return nil))
+ (setq srv-ls (nnmaildir--srv-get-ls nnmaildir--cur-server)
+ gname (nnmaildir--grp-get-name group)
+ pgname (nnmaildir--grp-get-pname group)
+ nlist (nnmaildir--grp-get-lists group)
+ flist (nnmaildir--lists-get-flist nlist)
+ nlist (nnmaildir--lists-get-nlist nlist))
+ (if nlist nil
+ (gnus-info-set-read info nil)
+ (gnus-info-set-marks info nil 'extend)
+ (throw 'return info))
+ (setq old-marks (cons 'read (gnus-info-read info))
+ old-marks (cons old-marks (gnus-info-marks info))
+ last (nnmaildir--nlist-last-num nlist)
+ always-marks (nnmaildir--param pgname 'always-marks)
+ never-marks (nnmaildir--param pgname 'never-marks)
+ dir (nnmaildir--srv-get-dir nnmaildir--cur-server)
+ dir (nnmaildir--srv-grp-dir dir gname)
+ dir (nnmaildir--nndir dir)
+ dir (concat dir "marks")
+ dir (file-name-as-directory dir)
+ ls (nnmaildir--param pgname 'directory-files)
+ ls (or ls srv-ls)
+ markdirs (funcall ls dir nil "\\`[^.]" 'nosort)
+ num (length markdirs)
+ new-mmth 1)
+ (while (<= new-mmth num) (setq new-mmth (* 2 new-mmth)))
+ (if (/= new-mmth 1) (setq new-mmth (1- new-mmth)))
+ (setq new-mmth (make-vector new-mmth 0)
+ old-mmth (nnmaildir--grp-get-mmth group))
+ (while markdirs
+ (setq mark (car markdirs) markdirs (cdr markdirs)
+ articles (concat dir mark)
+ articles (file-name-as-directory articles)
+ mark-sym (intern mark)
+ ranges nil)
+ (catch 'got-ranges
+ (if (memq mark-sym never-marks) (throw 'got-ranges nil))
+ (when (memq mark-sym always-marks)
+ (setq ranges (list (cons 1 last)))
+ (throw 'got-ranges nil))
+ (setq mtime (file-attributes articles)
+ mtime (nth 5 mtime))
+ (set (intern mark new-mmth) mtime)
+ (when (equal mtime (symbol-value (intern-soft mark old-mmth)))
+ (setq ranges (assq mark-sym old-marks))
+ (if ranges (setq ranges (cdr ranges)))
+ (throw 'got-ranges nil))
+ (setq articles (funcall ls articles nil "\\`[^.]" 'nosort))
+ (while articles
+ (setq article (car articles) articles (cdr articles)
+ article (nnmaildir--flist-art flist article))
+ (if article
+ (setq num (nnmaildir--art-get-num article)
+ ranges (gnus-add-to-range ranges (list num))))))
+ (if (eq mark-sym 'read) (setq read ranges)
+ (if ranges (setq marks (cons (cons mark-sym ranges) marks)))))
+ (gnus-info-set-read info read)
+ (gnus-info-set-marks info marks 'extend)
+ (nnmaildir--grp-set-mmth group new-mmth)
+ info)))
+
+(defun nnmaildir-request-group (gname &optional server fast)
+ (nnmaildir-request-scan gname server)
+ (let ((group (nnmaildir--prepare server gname))
+ ct-min deactivate-mark)
+ (save-excursion
+ (set-buffer nntp-server-buffer)
+ (erase-buffer)
+ (catch 'return
+ (if group nil
+ (insert "411 no such news group\n")
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "No such group: " gname))
+ (throw 'return nil))
+ (nnmaildir--srv-set-curgrp nnmaildir--cur-server group)
+ (if fast (throw 'return t))
+ (setq ct-min (nnmaildir--article-count group))
+ (insert "211 ")
+ (princ (car ct-min) nntp-server-buffer)
+ (insert " ")
+ (princ (cdr ct-min) nntp-server-buffer)
+ (insert " ")
+ (princ (nnmaildir--nlist-last-num
+ (nnmaildir--lists-get-nlist
+ (nnmaildir--grp-get-lists group)))
+ nntp-server-buffer)
+ (insert " " gname "\n")
+ t))))
+
+(defun nnmaildir-request-create-group (gname &optional server args)
+ (nnmaildir--prepare server nil)
+ (catch 'return
+ (let ((create-dir (nnmaildir--srv-get-create-dir nnmaildir--cur-server))
+ srv-dir dir groups)
+ (when (zerop (length gname))
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ "Invalid (empty) group name")
+ (throw 'return nil))
+ (when (eq (aref "." 0) (aref gname 0))
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ "Group names may not start with \".\"")
+ (throw 'return nil))
+ (when (save-match-data (string-match "[\0/\t]" gname))
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "Illegal characters (null, tab, or /) in group name: "
+ gname))
+ (throw 'return nil))
+ (setq groups (nnmaildir--srv-get-groups nnmaildir--cur-server))
+ (when (intern-soft gname groups)
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "Group already exists: " gname))
+ (throw 'return nil))
+ (setq srv-dir (nnmaildir--srv-get-dir nnmaildir--cur-server))
+ (if (file-name-absolute-p create-dir)
+ (setq dir (expand-file-name create-dir))
+ (setq dir srv-dir
+ dir (file-truename dir)
+ dir (concat dir create-dir)))
+ (setq dir (file-name-as-directory dir)
+ dir (concat dir gname))
+ (nnmaildir--mkdir dir)
+ (setq dir (file-name-as-directory dir))
+ (nnmaildir--mkdir (concat dir "tmp"))
+ (nnmaildir--mkdir (concat dir "new"))
+ (nnmaildir--mkdir (concat dir "cur"))
+ (setq create-dir (file-name-as-directory create-dir))
+ (make-symbolic-link (concat create-dir gname) (concat srv-dir gname))
+ (nnmaildir-request-scan 'find-new-groups))))
+
+(defun nnmaildir-request-rename-group (gname new-name &optional server)
+ (let ((group (nnmaildir--prepare server gname))
+ (coding-system-for-write nnheader-file-coding-system)
+ (buffer-file-coding-system nil)
+ (file-coding-system-alist nil)
+ srv-dir x groups)
+ (catch 'return
+ (if group nil
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "No such group: " gname))
+ (throw 'return nil))
+ (when (zerop (length new-name))
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ "Invalid (empty) group name")
+ (throw 'return nil))
+ (when (eq (aref "." 0) (aref new-name 0))
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ "Group names may not start with \".\"")
+ (throw 'return nil))
+ (when (save-match-data (string-match "[\0/\t]" new-name))
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "Illegal characters (null, tab, or /) in group name: "
+ new-name))
+ (throw 'return nil))
+ (if (string-equal gname new-name) (throw 'return t))
+ (when (intern-soft new-name
+ (nnmaildir--srv-get-groups nnmaildir--cur-server))
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "Group already exists: " new-name))
+ (throw 'return nil))
+ (setq srv-dir (nnmaildir--srv-get-dir nnmaildir--cur-server))
+ (condition-case err
+ (rename-file (concat srv-dir gname)
+ (concat srv-dir new-name))
+ (error
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "Error renaming link: "
+ (prin1-to-string err)))
+ (throw 'return nil)))
+ (setq x (nnmaildir--srv-get-groups nnmaildir--cur-server)
+ groups (make-vector (length x) 0))
+ (mapatoms (lambda (sym)
+ (if (eq (symbol-value sym) group) nil
+ (set (intern (symbol-name sym) groups)
+ (symbol-value sym))))
+ x)
+ (setq group (copy-sequence group))
+ (nnmaildir--grp-set-name group new-name)
+ (set (intern new-name groups) group)
+ (nnmaildir--srv-set-groups nnmaildir--cur-server groups)
+ t)))
+
+(defun nnmaildir-request-delete-group (gname force &optional server)
+ (let ((group (nnmaildir--prepare server gname))
+ pgname grp-dir dir dirs files ls deactivate-mark)
+ (catch 'return
+ (if group nil
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "No such group: " gname))
+ (throw 'return nil))
+ (if (eq group (nnmaildir--srv-get-curgrp nnmaildir--cur-server))
+ (nnmaildir--srv-set-curgrp nnmaildir--cur-server nil))
+ (setq gname (nnmaildir--grp-get-name group)
+ pgname (nnmaildir--grp-get-pname group))
+ (unintern gname (nnmaildir--srv-get-groups nnmaildir--cur-server))
+ (setq grp-dir (nnmaildir--srv-get-dir nnmaildir--cur-server)
+ grp-dir (nnmaildir--srv-grp-dir grp-dir gname))
+ (if (not force) (setq grp-dir (directory-file-name grp-dir))
+ (if (nnmaildir--param pgname 'read-only)
+ (progn (delete-directory (nnmaildir--tmp grp-dir))
+ (nnmaildir--unlink (nnmaildir--new grp-dir))
+ (delete-directory (nnmaildir--cur grp-dir)))
+ (save-excursion
+ (set-buffer (get-buffer-create " *nnmaildir work*"))
+ (erase-buffer)
+ (setq ls (or (nnmaildir--param pgname 'directory-files)
+ (nnmaildir--srv-get-ls nnmaildir--cur-server))
+ files (funcall ls (nnmaildir--tmp grp-dir) 'full "\\`[^.]"
+ 'nosort))
+ (while files
+ (delete-file (car files))
+ (setq files (cdr files)))
+ (delete-directory (concat grp-dir "tmp"))
+ (setq files (funcall ls (nnmaildir--new grp-dir) 'full "\\`[^.]"
+ 'nosort))
+ (while files
+ (delete-file (car files))
+ (setq files (cdr files)))
+ (delete-directory (concat grp-dir "new"))
+ (setq files (funcall ls (nnmaildir--cur grp-dir) 'full "\\`[^.]"
+ 'nosort))
+ (while files
+ (delete-file (car files))
+ (setq files (cdr files)))
+ (delete-directory (concat grp-dir "cur"))))
+ (setq dir (nnmaildir--nndir grp-dir)
+ dirs (cons (concat dir "nov")
+ (funcall ls (concat dir "marks") 'full "\\`[^.]"
+ 'nosort)))
+ (while dirs
+ (setq dir (car dirs) dirs (cdr dirs)
+ files (funcall ls dir 'full "\\`[^.]" 'nosort))
+ (while files
+ (delete-file (car files))
+ (setq files (cdr files)))
+ (delete-directory dir))
+ (setq dir (nnmaildir--nndir grp-dir)
+ files (concat dir "markfile"))
+ (nnmaildir--unlink files)
+ (delete-directory (concat dir "marks"))
+ (delete-directory dir)
+ (setq grp-dir (directory-file-name grp-dir)
+ dir (car (file-attributes grp-dir)))
+ (if (eq (aref "/" 0) (aref dir 0)) nil
+ (setq dir (concat (file-truename
+ (nnmaildir--srv-get-dir nnmaildir--cur-server))
+ dir)))
+ (delete-directory dir))
+ (nnmaildir--unlink grp-dir)
+ t)))
+
+(defun nnmaildir-retrieve-headers (articles &optional gname server fetch-old)
+ (let ((group (nnmaildir--prepare server gname))
+ srv-dir dir nlist mlist article num stop nov nlist2 deactivate-mark)
+ (catch 'return
+ (if group nil
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (if gname (concat "No such group: " gname)
+ "No current group"))
+ (throw 'return nil))
+ (save-excursion
+ (set-buffer nntp-server-buffer)
+ (erase-buffer)
+ (setq nlist (nnmaildir--grp-get-lists group)
+ mlist (nnmaildir--lists-get-mlist nlist)
+ nlist (nnmaildir--lists-get-nlist nlist)
+ gname (nnmaildir--grp-get-name group)
+ srv-dir (nnmaildir--srv-get-dir nnmaildir--cur-server)
+ dir (nnmaildir--srv-grp-dir srv-dir gname))
+ (cond
+ ((null nlist))
+ ((and fetch-old (not (numberp fetch-old)))
+ (while nlist
+ (setq article (car nlist) nlist (cdr nlist)
+ nov (nnmaildir--update-nov srv-dir group article))
+ (when nov
+ (nnmaildir--cache-nov group article nov)
+ (setq num (nnmaildir--art-get-num article))
+ (princ num nntp-server-buffer)
+ (insert "\t" (nnmaildir--nov-get-beg nov) "\t"
+ (nnmaildir--art-get-msgid article) "\t"
+ (nnmaildir--nov-get-mid nov) "\tXref: nnmaildir " gname
+ ":")
+ (princ num nntp-server-buffer)
+ (insert "\t" (nnmaildir--nov-get-end nov) "\n")
+ (goto-char (point-min)))))
+ ((null articles))
+ ((stringp (car articles))
+ (while articles
+ (setq article (car articles) articles (cdr articles)
+ article (nnmaildir--mlist-art mlist article))
+ (when (and article
+ (setq nov (nnmaildir--update-nov srv-dir group
+ article)))
+ (nnmaildir--cache-nov group article nov)
+ (setq num (nnmaildir--art-get-num article))
+ (princ num nntp-server-buffer)
+ (insert "\t" (nnmaildir--nov-get-beg nov) "\t"
+ (nnmaildir--art-get-msgid article) "\t"
+ (nnmaildir--nov-get-mid nov) "\tXref: nnmaildir " gname
+ ":")
+ (princ num nntp-server-buffer)
+ (insert "\t" (nnmaildir--nov-get-end nov) "\n"))))
+ (t
+ (if fetch-old
+ ;; Assume the article range is sorted ascending
+ (setq stop (car articles)
+ num (car (last articles))
+ stop (if (numberp stop) stop (car stop))
+ num (if (numberp num) num (cdr num))
+ stop (- stop fetch-old)
+ stop (if (< stop 1) 1 stop)
+ articles (list (cons stop num))))
+ (while articles
+ (setq stop (car articles) articles (cdr articles))
+ (while (eq stop (car articles))
+ (setq articles (cdr articles)))
+ (if (numberp stop) (setq num stop)
+ (setq num (cdr stop) stop (car stop)))
+ (setq nlist2 (nthcdr (- (nnmaildir--art-get-num (car nlist)) num)
+ nlist))
+ (while (and nlist2
+ (setq article (car nlist2)
+ num (nnmaildir--art-get-num article))
+ (>= num stop))
+ (setq nlist2 (cdr nlist2)
+ nov (nnmaildir--update-nov srv-dir group article))
+ (when nov
+ (nnmaildir--cache-nov group article nov)
+ (princ num nntp-server-buffer)
+ (insert "\t" (nnmaildir--nov-get-beg nov) "\t"
+ (nnmaildir--art-get-msgid article) "\t"
+ (nnmaildir--nov-get-mid nov) "\tXref: nnmaildir " gname
+ ":")
+ (princ num nntp-server-buffer)
+ (insert "\t" (nnmaildir--nov-get-end nov) "\n")
+ (goto-char (point-min)))))))
+ (sort-numeric-fields 1 (point-min) (point-max))
+ 'nov))))
+
+(defun nnmaildir-request-article (num-msgid &optional gname server to-buffer)
+ (let ((group (nnmaildir--prepare server gname))
+ (case-fold-search t)
+ list article suffix dir deactivate-mark)
+ (catch 'return
+ (if group nil
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (if gname (concat "No such group: " gname)
+ "No current group"))
+ (throw 'return nil))
+ (setq list (nnmaildir--grp-get-lists group))
+ (if (numberp num-msgid)
+ (setq list (nnmaildir--lists-get-nlist list)
+ article (nnmaildir--nlist-art list num-msgid))
+ (setq list (nnmaildir--lists-get-mlist list)
+ article (nnmaildir--mlist-art list num-msgid))
+ (if article (setq num-msgid (nnmaildir--art-get-num article))
+ (catch 'found
+ (mapatoms
+ (lambda (grp)
+ (setq group (symbol-value grp)
+ list (nnmaildir--grp-get-lists group)
+ list (nnmaildir--lists-get-mlist list)
+ article (nnmaildir--mlist-art list num-msgid))
+ (when article
+ (setq num-msgid (nnmaildir--art-get-num article))
+ (throw 'found nil)))
+ (nnmaildir--srv-get-groups nnmaildir--cur-server)))))
+ (if article nil
+ (nnmaildir--srv-set-error nnmaildir--cur-server "No such article")
+ (throw 'return nil))
+ (if (stringp (setq suffix (nnmaildir--art-get-suffix article))) nil
+ (nnmaildir--srv-set-error nnmaildir--cur-server "Article has expired")
+ (throw 'return nil))
+ (setq gname (nnmaildir--grp-get-name group)
+ dir (nnmaildir--srv-get-dir nnmaildir--cur-server)
+ dir (nnmaildir--srv-grp-dir dir gname)
+ group (if (nnmaildir--param (nnmaildir--grp-get-pname group)
+ 'read-only)
+ (nnmaildir--new dir) (nnmaildir--cur dir))
+ nnmaildir-article-file-name (concat group
+ (nnmaildir--art-get-prefix
+ article)
+ suffix))
+ (if (file-exists-p nnmaildir-article-file-name) nil
+ (nnmaildir--art-set-suffix article 'expire)
+ (nnmaildir--art-set-nov article nil)
+ (nnmaildir--srv-set-error nnmaildir--cur-server "Article has expired")
+ (throw 'return nil))
+ (save-excursion
+ (set-buffer (or to-buffer nntp-server-buffer))
+ (erase-buffer)
+ (nnheader-insert-file-contents nnmaildir-article-file-name))
+ (cons gname num-msgid))))
+
+(defun nnmaildir-request-post (&optional server)
+ (let (message-required-mail-headers)
+ (funcall message-send-mail-function)))
+
+(defun nnmaildir-request-replace-article (article gname buffer)
+ (let ((group (nnmaildir--prepare nil gname))
+ (coding-system-for-write nnheader-file-coding-system)
+ (buffer-file-coding-system nil)
+ (file-coding-system-alist nil)
+ file dir suffix tmpfile deactivate-mark)
+ (catch 'return
+ (if group nil
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "No such group: " gname))
+ (throw 'return nil))
+ (when (nnmaildir--param (nnmaildir--grp-get-pname group) 'read-only)
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "Read-only group: " group))
+ (throw 'return nil))
+ (setq dir (nnmaildir--srv-get-dir nnmaildir--cur-server)
+ dir (nnmaildir--srv-grp-dir dir gname)
+ file (nnmaildir--grp-get-lists group)
+ file (nnmaildir--lists-get-nlist file)
+ file (nnmaildir--nlist-art file article))
+ (if (and file (stringp (setq suffix (nnmaildir--art-get-suffix file))))
+ nil
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (format "No such article: %d" article))
+ (throw 'return nil))
+ (save-excursion
+ (set-buffer buffer)
+ (setq article file
+ file (nnmaildir--art-get-prefix article)
+ tmpfile (concat (nnmaildir--tmp dir) file))
+ (when (file-exists-p tmpfile)
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "File exists: " tmpfile))
+ (throw 'return nil))
+ (write-region (point-min) (point-max) tmpfile nil 'no-message nil
+ 'confirm-overwrite)) ;; error would be preferred :(
+ (unix-sync) ;; no fsync :(
+ (rename-file tmpfile (concat (nnmaildir--cur dir) file suffix) 'replace)
+ t)))
+
+(defun nnmaildir-request-move-article (article gname server accept-form
+ &optional last)
+ (let ((group (nnmaildir--prepare server gname))
+ pgname list suffix result nnmaildir--file deactivate-mark)
+ (catch 'return
+ (if group nil
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "No such group: " gname))
+ (throw 'return nil))
+ (setq gname (nnmaildir--grp-get-name group)
+ pgname (nnmaildir--grp-get-pname group)
+ list (nnmaildir--grp-get-lists group)
+ list (nnmaildir--lists-get-nlist list)
+ article (nnmaildir--nlist-art list article))
+ (if article nil
+ (nnmaildir--srv-set-error nnmaildir--cur-server "No such article")
+ (throw 'return nil))
+ (if (stringp (setq suffix (nnmaildir--art-get-suffix article))) nil
+ (nnmaildir--srv-set-error nnmaildir--cur-server "Article has expired")
+ (throw 'return nil))
+ (setq nnmaildir--file (nnmaildir--srv-get-dir nnmaildir--cur-server)
+ nnmaildir--file (nnmaildir--srv-grp-dir nnmaildir--file gname)
+ nnmaildir--file (if (nnmaildir--param pgname 'read-only)
+ (nnmaildir--new nnmaildir--file)
+ (nnmaildir--cur nnmaildir--file))
+ nnmaildir--file (concat nnmaildir--file
+ (nnmaildir--art-get-prefix article)
+ suffix))
+ (if (file-exists-p nnmaildir--file) nil
+ (nnmaildir--art-set-suffix article 'expire)
+ (nnmaildir--art-set-nov article nil)
+ (nnmaildir--srv-set-error nnmaildir--cur-server "Article has expired")
+ (throw 'return nil))
+ (save-excursion
+ (set-buffer (get-buffer-create " *nnmaildir move*"))
+ (erase-buffer)
+ (nnheader-insert-file-contents nnmaildir--file)
+ (setq result (eval accept-form)))
+ (if (or (null result) (nnmaildir--param pgname 'read-only)) nil
+ (nnmaildir--unlink nnmaildir--file)
+ (nnmaildir--art-set-suffix article 'expire)
+ (nnmaildir--art-set-nov article nil))
+ result)))
+
+(defun nnmaildir-request-accept-article (gname &optional server last)
+ (let ((group (nnmaildir--prepare server gname))
+ (coding-system-for-write nnheader-file-coding-system)
+ (buffer-file-coding-system nil)
+ (file-coding-system-alist nil)
+ srv-dir dir file tmpfile curfile 24h num article)
+ (catch 'return
+ (if group nil
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "No such group: " gname))
+ (throw 'return nil))
+ (setq gname (nnmaildir--grp-get-name group))
+ (when (nnmaildir--param (nnmaildir--grp-get-pname group) 'read-only)
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "Read-only group: " gname))
+ (throw 'return nil))
+ (setq srv-dir (nnmaildir--srv-get-dir nnmaildir--cur-server)
+ dir (nnmaildir--srv-grp-dir srv-dir gname)
+ file (format-time-string "%s" nil))
+ (if (string= nnmaildir--delivery-time file) nil
+ (setq nnmaildir--delivery-time file
+ nnmaildir--delivery-ct 0))
+ (setq file (concat file "." nnmaildir--delivery-pid))
+ (if (zerop nnmaildir--delivery-ct) nil
+ (setq file (concat file "_"
+ (number-to-string nnmaildir--delivery-ct))))
+ (setq file (concat file "." (system-name))
+ tmpfile (concat (nnmaildir--tmp dir) file)
+ curfile (concat (nnmaildir--cur dir) file ":2,"))
+ (when (file-exists-p tmpfile)
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "File exists: " tmpfile))
+ (throw 'return nil))
+ (when (file-exists-p curfile)
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "File exists: " curfile))
+ (throw 'return nil))
+ (setq nnmaildir--delivery-ct (1+ nnmaildir--delivery-ct)
+ 24h (run-with-timer 86400 nil
+ (lambda ()
+ (nnmaildir--unlink tmpfile)
+ (nnmaildir--srv-set-error
+ nnmaildir--cur-server
+ "24-hour timer expired")
+ (throw 'return nil))))
+ (condition-case nil
+ (add-name-to-file nnmaildir--file tmpfile)
+ (error
+ (write-region (point-min) (point-max) tmpfile nil 'no-message nil
+ 'confirm-overwrite) ;; error would be preferred :(
+ (unix-sync))) ;; no fsync :(
+ (cancel-timer 24h)
+ (condition-case err
+ (add-name-to-file tmpfile curfile)
+ (error
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "Error linking: "
+ (prin1-to-string err)))
+ (nnmaildir--unlink tmpfile)
+ (throw 'return nil)))
+ (nnmaildir--unlink tmpfile)
+ (setq article (nnmaildir--art-new)
+ num (nnmaildir--grp-get-lists group)
+ num (nnmaildir--lists-get-nlist num)
+ num (1+ (nnmaildir--nlist-last-num num)))
+ (nnmaildir--art-set-prefix article file)
+ (nnmaildir--art-set-suffix article ":2,")
+ (nnmaildir--art-set-num article num)
+ (if (nnmaildir--grp-add-art srv-dir group article) (cons gname num)))))
+
+(defun nnmaildir-save-mail (group-art)
+ (catch 'return
+ (if group-art nil
+ (throw 'return nil))
+ (let ((ret group-art)
+ ga gname x groups nnmaildir--file deactivate-mark)
+ (save-excursion
+ (goto-char (point-min))
+ (save-match-data
+ (while (looking-at "From ")
+ (replace-match "X-From-Line: ")
+ (forward-line 1))))
+ (setq groups (nnmaildir--srv-get-groups nnmaildir--cur-server)
+ ga (car group-art) group-art (cdr group-art)
+ gname (car ga))
+ (or (intern-soft gname groups)
+ (nnmaildir-request-create-group gname)
+ (throw 'return nil)) ;; not that nnmail bothers to check :(
+ (if (nnmaildir-request-accept-article gname) nil
+ (throw 'return nil))
+ (setq x (nnmaildir--prepare nil gname)
+ nnmaildir--file (nnmaildir--srv-get-dir nnmaildir--cur-server)
+ nnmaildir--file (concat nnmaildir--file
+ (nnmaildir--grp-get-name x))
+ nnmaildir--file (file-name-as-directory nnmaildir--file)
+ x (nnmaildir--grp-get-lists x)
+ x (nnmaildir--lists-get-nlist x)
+ x (car x)
+ nnmaildir--file (concat nnmaildir--file
+ (nnmaildir--art-get-prefix x)
+ (nnmaildir--art-get-suffix x)))
+ (while group-art
+ (setq ga (car group-art) group-art (cdr group-art)
+ gname (car ga))
+ (if (and (or (intern-soft gname groups)
+ (nnmaildir-request-create-group gname))
+ (nnmaildir-request-accept-article gname)) nil
+ (setq ret (delq ga ret)))) ;; We'll still try the other groups
+ ret)))
+
+(defun nnmaildir-active-number (group)
+ (let ((x (nnmaildir--prepare nil group)))
+ (catch 'return
+ (if x nil
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "No such group: " group))
+ (throw 'return nil))
+ (setq x (nnmaildir--grp-get-lists x)
+ x (nnmaildir--lists-get-nlist x))
+ (if x
+ (setq x (car x)
+ x (nnmaildir--art-get-num x)
+ x (1+ x))
+ 1))))
+
+(defun nnmaildir-request-expire-articles (ranges &optional gname server force)
+ (let ((no-force (not force))
+ (group (nnmaildir--prepare server gname))
+ pgname time boundary time-iter bound-iter high low target dir nlist
+ stop num article didnt suffix nnmaildir--file deactivate-mark)
+ (catch 'return
+ (if group nil
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (if gname (concat "No such group: " gname)
+ "No current group"))
+ (throw 'return (gnus-uncompress-range ranges)))
+ (setq gname (nnmaildir--grp-get-name group)
+ pgname (nnmaildir--grp-get-pname group))
+ (if (nnmaildir--param pgname 'read-only)
+ (throw 'return (gnus-uncompress-range ranges)))
+ (setq time (or (nnmaildir--param pgname 'expire-age) 604800))
+ (if (or force (integerp time)) nil
+ (throw 'return (gnus-uncompress-range ranges)))
+ (setq boundary (current-time)
+ high (- (car boundary) (/ time 65536))
+ low (- (cadr boundary) (% time 65536)))
+ (if (< low 0)
+ (setq low (+ low 65536)
+ high (1- high)))
+ (setcar (cdr boundary) low)
+ (setcar boundary high)
+ (setq target (nnmaildir--param pgname 'expire-group)
+ target (and (stringp target)
+ (not (string-equal target pgname))
+ target)
+ dir (nnmaildir--srv-get-dir nnmaildir--cur-server)
+ dir (nnmaildir--srv-grp-dir dir gname)
+ dir (nnmaildir--cur dir)
+ nlist (nnmaildir--grp-get-lists group)
+ nlist (nnmaildir--lists-get-nlist nlist)
+ ranges (reverse ranges))
+ (save-excursion
+ (set-buffer (get-buffer-create " *nnmaildir move*"))
+ (while ranges
+ (setq num (car ranges) ranges (cdr ranges))
+ (while (eq num (car ranges))
+ (setq ranges (cdr ranges)))
+ (if (numberp num) (setq stop num)
+ (setq stop (car num) num (cdr num)))
+ (setq nlist (nthcdr (- (nnmaildir--art-get-num (car nlist)) num)
+ nlist))
+ (while (and nlist
+ (setq article (car nlist)
+ num (nnmaildir--art-get-num article))
+ (>= num stop))
+ (setq nlist (cdr nlist)
+ suffix (nnmaildir--art-get-suffix article))
+ (catch 'continue
+ (if (stringp suffix) nil
+ (nnmaildir--art-set-suffix article 'expire)
+ (nnmaildir--art-set-nov article nil)
+ (throw 'continue nil))
+ (setq nnmaildir--file (nnmaildir--art-get-prefix article)
+ nnmaildir--file (concat dir nnmaildir--file suffix)
+ time (file-attributes nnmaildir--file))
+ (if time nil
+ (nnmaildir--art-set-suffix article 'expire)
+ (nnmaildir--art-set-nov article nil)
+ (throw 'continue nil))
+ (setq time (nth 5 time)
+ time-iter time
+ bound-iter boundary)
+ (if (and no-force
+ (progn
+ (while (and bound-iter time-iter
+ (= (car bound-iter) (car time-iter)))
+ (setq bound-iter (cdr bound-iter)
+ time-iter (cdr time-iter)))
+ (and bound-iter time-iter
+ (car-less-than-car bound-iter time-iter))))
+ (setq didnt (cons (nnmaildir--art-get-num article) didnt))
+ (when target
+ (erase-buffer)
+ (nnheader-insert-file-contents nnmaildir--file)
+ (gnus-request-accept-article target nil nil 'no-encode))
+ (nnmaildir--unlink nnmaildir--file)
+ (nnmaildir--art-set-suffix article 'expire)
+ (nnmaildir--art-set-nov article nil)))))
+ (erase-buffer))
+ didnt)))
+
+(defun nnmaildir-request-set-mark (gname actions &optional server)
+ (let ((group (nnmaildir--prepare server gname))
+ (coding-system-for-write nnheader-file-coding-system)
+ (buffer-file-coding-system nil)
+ (file-coding-system-alist nil)
+ del-mark add-marks marksdir markfile action group-nlist nlist ranges
+ begin end article all-marks todo-marks did-marks marks form mdir mfile
+ deactivate-mark)
+ (setq del-mark
+ (lambda ()
+ (setq mfile (car marks)
+ mfile (symbol-name mfile)
+ mfile (concat marksdir mfile)
+ mfile (file-name-as-directory mfile)
+ mfile (concat mfile (nnmaildir--art-get-prefix article)))
+ (nnmaildir--unlink mfile))
+ add-marks
+ (lambda ()
+ (while marks
+ (setq mdir (concat marksdir (symbol-name (car marks)))
+ mfile (concat (file-name-as-directory mdir)
+ (nnmaildir--art-get-prefix article)))
+ (if (memq (car marks) did-marks) nil
+ (nnmaildir--mkdir mdir)
+ (setq did-marks (cons (car marks) did-marks)))
+ (if (file-exists-p mfile) nil
+ (condition-case nil
+ (add-name-to-file markfile mfile)
+ (file-error ;; too many links, probably
+ (if (file-exists-p mfile) nil
+ (nnmaildir--unlink markfile)
+ (write-region "" nil markfile nil 'no-message)
+ (add-name-to-file markfile mfile
+ 'ok-if-already-exists)))))
+ (setq marks (cdr marks)))))
+ (catch 'return
+ (if group nil
+ (nnmaildir--srv-set-error nnmaildir--cur-server
+ (concat "No such group: " gname))
+ (while actions
+ (setq ranges (gnus-range-add ranges (caar actions))
+ actions (cdr actions)))
+ (throw 'return ranges))
+ (setq group-nlist (nnmaildir--grp-get-lists group)
+ group-nlist (nnmaildir--lists-get-nlist group-nlist)
+ marksdir (nnmaildir--srv-get-dir nnmaildir--cur-server)
+ marksdir (nnmaildir--srv-grp-dir marksdir gname)
+ marksdir (nnmaildir--nndir marksdir)
+ markfile (concat marksdir "markfile")
+ marksdir (concat marksdir "marks")
+ marksdir (file-name-as-directory marksdir)
+ gname (nnmaildir--grp-get-name group)
+ all-marks (nnmaildir--grp-get-pname group)
+ all-marks (or (nnmaildir--param all-marks 'directory-files)
+ (nnmaildir--srv-get-ls nnmaildir--cur-server))
+ all-marks (funcall all-marks marksdir nil "\\`[^.]" 'nosort)
+ marks all-marks)
+ (while marks
+ (setcar marks (intern (car marks)))
+ (setq marks (cdr marks)))
+ (while actions
+ (setq action (car actions) actions (cdr actions)
+ nlist group-nlist
+ ranges (car action)
+ todo-marks (caddr action)
+ marks todo-marks)
+ (while marks
+ (if (memq (car marks) all-marks) nil
+ (setq all-marks (cons (car marks) all-marks)))
+ (setq marks (cdr marks)))
+ (setq form
+ (cond
+ ((eq 'del (cadr action))
+ '(while marks
+ (funcall del-mark)
+ (setq marks (cdr marks))))
+ ((eq 'add (cadr action)) '(funcall add-marks))
+ (t
+ '(progn
+ (funcall add-marks)
+ (setq marks all-marks)
+ (while marks
+ (if (memq (car marks) todo-marks) nil
+ (funcall del-mark))
+ (setq marks (cdr marks)))))))
+ (if (numberp (cdr ranges)) (setq ranges (list ranges))
+ (setq ranges (reverse ranges)))
+ (while ranges
+ (setq begin (car ranges) ranges (cdr ranges))
+ (while (eq begin (car ranges))
+ (setq ranges (cdr ranges)))
+ (if (numberp begin) (setq end begin)
+ (setq end (cdr begin) begin (car begin)))
+ (setq nlist (nthcdr (- (nnmaildir--art-get-num (car nlist)) end)
+ nlist))
+ (while (and nlist
+ (setq article (car nlist))
+ (>= (nnmaildir--art-get-num article) begin))
+ (setq nlist (cdr nlist))
+ (when (stringp (nnmaildir--art-get-suffix article))
+ (setq marks todo-marks)
+ (eval form)))))
+ nil)))
+
+(defun nnmaildir-close-group (group &optional server)
+ t)
+
+(defun nnmaildir-close-server (&optional server)
+ (let (srv-ls flist ls dirs dir files file x)
+ (nnmaildir--prepare server nil)
+ (setq server nnmaildir--cur-server)
+ (when server
+ (setq nnmaildir--cur-server nil
+ srv-ls (nnmaildir--srv-get-ls server))
+ (save-match-data
+ (mapatoms
+ (lambda (group)
+ (setq group (symbol-value group)
+ x (nnmaildir--grp-get-pname group)
+ ls (nnmaildir--param x 'directory-files)
+ ls (or ls srv-ls)
+ dir (nnmaildir--srv-get-dir server)
+ dir (nnmaildir--srv-grp-dir
+ dir (nnmaildir--grp-get-name group))
+ x (nnmaildir--param x 'read-only)
+ x (if x (nnmaildir--new dir) (nnmaildir--cur dir))
+ files (funcall ls x nil "\\`[^.]" 'nosort)
+ x (length files)
+ flist 1)
+ (while (<= flist x) (setq flist (* 2 flist)))
+ (if (/= flist 1) (setq flist (1- flist)))
+ (setq flist (make-vector flist 0))
+ (while files
+ (setq file (car files) files (cdr files))
+ (string-match "\\`\\([^:]*\\)\\(:.*\\)?\\'" file)
+ (intern (match-string 1 file) flist))
+ (setq dir (nnmaildir--nndir dir)
+ dirs (cons (concat dir "nov")
+ (funcall ls (concat dir "marks") 'full "\\`[^.]"
+ 'nosort)))
+ (while dirs
+ (setq dir (car dirs) dirs (cdr dirs)
+ files (funcall ls dir nil "\\`[^.]" 'nosort)
+ dir (file-name-as-directory dir))
+ (while files
+ (setq file (car files) files (cdr files))
+ (if (intern-soft file flist) nil
+ (setq file (concat dir file))
+ (delete-file file)))))
+ (nnmaildir--srv-get-groups server)))
+ (unintern (nnmaildir--srv-get-name server) nnmaildir--servers)))
+ t)
+
+(defun nnmaildir-request-close ()
+ (let (servers buffer)
+ (mapatoms (lambda (server)
+ (setq servers (cons (symbol-name server) servers)))
+ nnmaildir--servers)
+ (while servers
+ (nnmaildir-close-server (car servers))
+ (setq servers (cdr servers)))
+ (setq buffer (get-buffer " *nnmaildir work*"))
+ (if buffer (kill-buffer buffer))
+ (setq buffer (get-buffer " *nnmaildir nov*"))
+ (if buffer (kill-buffer buffer))
+ (setq buffer (get-buffer " *nnmaildir move*"))
+ (if buffer (kill-buffer buffer)))
+ t)
+
+(provide 'nnmaildir)
+
+;;; nnmaildir.el ends here
(car active) (cdr active) group)))))
(defun nnmbox-save-buffer ()
- (let ((coding-system-for-write
+ (let ((coding-system-for-write
(or nnmbox-file-coding-system-for-write
nnmbox-file-coding-system)))
(save-buffer)))
(progn
(unless (eq nnmail-expiry-target 'delete)
(with-temp-buffer
- (nnmbox-request-article (car articles)
- newsgroup server
+ (nnmbox-request-article (car articles)
+ newsgroup server
(current-buffer))
(let ((nnml-current-directory nil))
(nnmail-expiry-target-group
- nnmail-expiry-target newsgroup))))
+ nnmail-expiry-target newsgroup)))
+ (nnmbox-possibly-change-newsgroup newsgroup server))
(nnheader-message 5 "Deleting article %d in %s..."
(car articles) newsgroup)
(nnmbox-delete-mail))
(nnmbox-in-header-p (point)))
(progn
(goto-char (point-min))
- (while (not found)
- (setq found (and (search-forward art-string nil t)
- (nnmbox-in-header-p (point)))))
+ (while (and (not found)
+ (search-forward art-string nil t))
+ (setq found (nnmbox-in-header-p (point))))
found)))))
(defun nnmbox-record-active-article (group-art)
(when (not (file-exists-p nnmbox-mbox-file))
(let ((nnmail-file-coding-system
(or nnmbox-file-coding-system-for-write
- nnmbox-file-coding-system)))
+ nnmbox-file-coding-system))
+ (dir (file-name-directory nnmbox-mbox-file)))
+ (and dir (gnus-make-directory dir))
(nnmail-write-region 1 1 nnmbox-mbox-file t 'nomesg))))
(defun nnmbox-read-mbox ()
(let ((nnheader-file-coding-system
nnmbox-file-coding-system))
(nnheader-find-file-noselect
- nnmbox-mbox-file nil t))))
+ nnmbox-mbox-file t t))))
(mm-enable-multibyte)
(buffer-disable-undo)
;;; nnmh.el --- mhspool access for Gnus
-;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
(nnoo-declare nnmh)
(defvoo nnmh-directory message-directory
- "*Mail spool directory.")
+ "Mail spool directory.")
(defvoo nnmh-get-new-mail t
- "*If non-nil, nnmh will check the incoming mail file and split the mail.")
+ "If non-nil, nnmh will check the incoming mail file and split the mail.")
(defvoo nnmh-prepare-save-mail-hook nil
- "*Hook run narrowed to an article before saving.")
+ "Hook run narrowed to an article before saving.")
(defvoo nnmh-be-safe nil
- "*If non-nil, nnmh will check all articles to make sure whether they are new or not.
+ "If non-nil, nnmh will check all articles to make sure whether they are new or not.
Go through the .nnmh-articles file and compare with the actual
articles in this folder. The articles that are \"new\" will be marked
as unread by Gnus.")
(file-truename (file-name-as-directory
(expand-file-name nnmh-toplev))))
dir)
- (nnheader-replace-chars-in-string
- (mm-decode-coding-string (substring dir (match-end 0))
- nnmail-pathname-coding-system)
- ?/ ?.))
+ (mm-string-as-multibyte
+ (mm-encode-coding-string
+ (nnheader-replace-chars-in-string
+ (substring dir (match-end 0))
+ ?/ ?.)
+ nnmail-pathname-coding-system)))
(apply 'max files)
(apply 'min files)))))))
t)
(file-name-coding-system nnmail-pathname-coding-system))
(if (file-directory-p pathname)
(setq nnmh-current-directory pathname)
- (error "No such newsgroup: %s" newsgroup)))))
+ (nnheader-report 'nnmh "Not a directory: %s" nnmh-directory)))))
(defun nnmh-possibly-create-directory (group)
(let (dir dirs)
;;; nnml.el --- mail spool access for Gnus
-;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
-;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
+;; Author: Simon Josefsson <simon@josefsson.org> (adding MARKS)
+;; Lars Magne Ingebrigtsen <larsi@gnus.org>
;; Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
;; Keywords: news, mail
;;; Code:
+(require 'gnus)
(require 'nnheader)
(require 'nnmail)
(require 'nnoo)
(eval-when-compile (require 'cl))
+(eval-and-compile
+ (autoload 'gnus-article-unpropagatable-p "gnus-sum"))
+
(nnoo-declare nnml)
(defvoo nnml-directory message-directory
"If non-nil, nnml will check the incoming mail file and split the mail.")
(defvoo nnml-nov-is-evil nil
- "If non-nil, Gnus will never generate and use nov databases for mail groups.
+ "If non-nil, Gnus will never generate and use nov databases for mail spools.
Using nov databases will speed up header fetching considerably.
This variable shouldn't be flipped much. If you have, for some reason,
set this to t, and want to set it to nil again, you should always run
through all nnml directories and generate nov databases for them
all. This may very well take some time.")
+(defvoo nnml-marks-is-evil nil
+ "If non-nil, Gnus will never generate and use marks file for mail spools.
+Using marks files makes it possible to backup and restore mail groups
+separately from `.newsrc.eld'. If you have, for some reason, set this
+to t, and want to set it to nil again, you should always remove the
+corresponding marks file (usually named `.marks' in the nnml group
+directory, but see `nnml-marks-file-name') for the group. Then the
+marks file will be regenerated properly by Gnus.")
+
+(defvoo nnml-filenames-are-evil t
+ "If non-nil, Gnus will not assume that the articles file name
+is the same as the article number listed in the nov database. This
+variable should be set if any of the files are compressed.")
+
(defvoo nnml-prepare-save-mail-hook nil
"Hook run narrowed to an article before saving.")
"nnml version.")
(defvoo nnml-nov-file-name ".overview")
+(defvoo nnml-marks-file-name ".marks")
(defvoo nnml-current-directory nil)
(defvoo nnml-current-group nil)
(defvoo nnml-file-coding-system nnmail-file-coding-system)
-\f
+(defvoo nnml-marks nil)
+(defvar nnml-marks-modtime (gnus-make-hashtable))
+
+\f
;;; Interface functions.
(nnoo-define-basics nnml)
(save-excursion
(set-buffer nntp-server-buffer)
(erase-buffer)
- (let ((file nil)
- (number (length sequence))
- (count 0)
- (file-name-coding-system nnmail-pathname-coding-system)
- beg article)
+ (let* ((file nil)
+ (number (length sequence))
+ (count 0)
+ (file-name-coding-system nnmail-pathname-coding-system)
+ beg article)
(if (stringp (car sequence))
'headers
(if (nnml-retrieve-headers-with-nov sequence fetch-old)
(setq beg (point))
(nnheader-insert-head file)
(goto-char beg)
- (if (search-forward "\n\n" nil t)
+ (if (re-search-forward "\n\r?\n" nil t)
(forward-char -1)
(goto-char (point-max))
(insert "\n\n"))
nnml-group-alist)
(nnml-possibly-create-directory group)
(nnml-possibly-change-directory group server)
- (let ((articles (nnheader-directory-articles nnml-current-directory)))
+ (let ((articles (nnml-directory-articles nnml-current-directory)))
(when articles
(setcar active (apply 'min articles))
(setcdr active (apply 'max articles))))
(deffoo nnml-request-expire-articles (articles group &optional server force)
(nnml-possibly-change-directory group server)
(let ((active-articles
- (nnheader-directory-articles nnml-current-directory))
+ (nnml-directory-articles nnml-current-directory))
(is-old t)
article rest mod-time number)
(nnmail-activate 'nnml)
(setq articles (gnus-sorted-intersection articles active-articles))
(while (and articles is-old)
- (when (setq article (nnml-article-to-file (setq number (pop articles))))
- (when (setq mod-time (nth 5 (file-attributes article)))
- (if (and (nnml-deletable-article-p group number)
- (setq is-old
- (nnmail-expired-article-p group mod-time force
- nnml-inhibit-expiry)))
- (progn
- ;; Allow a special target group.
- (unless (eq nnmail-expiry-target 'delete)
- (with-temp-buffer
- (nnml-request-article number group server
- (current-buffer))
- (let ((nnml-current-directory nil))
- (nnmail-expiry-target-group
- nnmail-expiry-target group))))
- (nnheader-message 5 "Deleting article %s in %s"
- number group)
- (condition-case ()
- (funcall nnmail-delete-file-function article)
- (file-error
- (push number rest)))
- (setq active-articles (delq number active-articles))
- (nnml-nov-delete-article group number))
- (push number rest)))))
+ (if (and (setq article (nnml-article-to-file (setq number (pop articles))))
+ (setq mod-time (nth 5 (file-attributes article)))
+ (nnml-deletable-article-p group number)
+ (setq is-old (nnmail-expired-article-p group mod-time force
+ nnml-inhibit-expiry)))
+ (progn
+ ;; Allow a special target group.
+ (unless (eq nnmail-expiry-target 'delete)
+ (with-temp-buffer
+ (nnml-request-article number group server (current-buffer))
+ (let (nnml-current-directory
+ nnml-current-group
+ nnml-article-file-alist)
+ (nnmail-expiry-target-group nnmail-expiry-target group)))
+ ;; Maybe directory is changed during nnmail-expiry-target-group.
+ (nnml-possibly-change-directory group server))
+ (nnheader-message 5 "Deleting article %s in %s"
+ number group)
+ (condition-case ()
+ (funcall nnmail-delete-file-function article)
+ (file-error
+ (push number rest)))
+ (setq active-articles (delq number active-articles))
+ (nnml-nov-delete-article group number))
+ (push number rest)))
(let ((active (nth 1 (assoc group nnml-group-alist))))
(when active
(setcar active (or (and active-articles
(and
(nnml-deletable-article-p group article)
(nnml-request-article article group server)
- (let (nnml-current-directory
- nnml-current-group
+ (let (nnml-current-directory
+ nnml-current-group
nnml-article-file-alist)
(save-excursion
(set-buffer buf)
(nnml-save-nov))))
result))
+(deffoo nnml-request-post (&optional server)
+ (nnmail-do-request-post 'nnml-request-accept-article server))
+
(deffoo nnml-request-replace-article (article group buffer)
(nnml-possibly-change-directory group)
(save-excursion
(directory-files
nnml-current-directory t
(concat nnheader-numerical-short-files
- "\\|" (regexp-quote nnml-nov-file-name) "$")))
+ "\\|" (regexp-quote nnml-nov-file-name) "$"
+ "\\|" (regexp-quote nnml-marks-file-name) "$")))
article)
(while articles
(setq article (pop articles))
(let ((overview (concat old-dir nnml-nov-file-name)))
(when (file-exists-p overview)
(rename-file overview (concat new-dir nnml-nov-file-name))))
+ ;; Move .marks file.
+ (let ((marks (concat old-dir nnml-marks-file-name)))
+ (when (file-exists-p marks)
+ (rename-file marks (concat new-dir nnml-marks-file-name))))
(when (<= (length (directory-files old-dir)) 2)
(ignore-errors (delete-directory old-dir)))
;; That went ok, so we change the internal structures.
(let (file)
(if (setq file (cdr (assq article nnml-article-file-alist)))
(expand-file-name file nnml-current-directory)
- ;; Just to make sure nothing went wrong when reading over NFS --
- ;; check once more.
- (when (file-exists-p
- (setq file (expand-file-name (number-to-string article)
- nnml-current-directory)))
- (nnml-update-file-alist t)
- file))))
+ (if (not nnheader-directory-files-is-safe)
+ ;; Just to make sure nothing went wrong when reading over NFS --
+ ;; check once more.
+ (when (file-exists-p
+ (setq file (expand-file-name (number-to-string article)
+ nnml-current-directory)))
+ (nnml-update-file-alist t)
+ file)))))
(defun nnml-deletable-article-p (group article)
"Say whether ARTICLE in GROUP can be deleted."
;; likely that the article we are looking for is in that group.
(if (setq number (nnml-find-id nnml-current-group id))
(cons nnml-current-group number)
- ;; It wasn't there, so we look through the other groups as well.
+ ;; It wasn't there, so we look through the other groups as well.
(while (and (not number)
alist)
(or (string= (caar alist) nnml-current-group)
(unless nnml-article-file-alist
(setq nnml-article-file-alist
(sort
- (nnheader-article-to-file-alist nnml-current-directory)
+ (nnml-current-group-article-to-file-alist)
'car-less-than-car)))
(setq active
(if nnml-article-file-alist
(unless (zerop (buffer-size))
(narrow-to-region
(goto-char (point-min))
- (if (search-forward "\n\n" nil t) (1- (point)) (point-max))))
+ (if (re-search-forward "\n\r?\n" nil t) (1- (point)) (point-max))))
;; Fold continuation lines.
(goto-char (point-min))
(while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t)
(replace-match " " t t))
;; Remove any tabs; they are too confusing.
(subst-char-in-region (point-min) (point-max) ?\t ? )
+ ;; Remove any ^M's; they are too confusing.
+ (subst-char-in-region (point-min) (point-max) ?\r ? )
(let ((headers (nnheader-parse-head t)))
(mail-header-set-chars headers chars)
(mail-header-set-number headers number)
headers))))
+(defun nnml-get-nov-buffer (group)
+ (let ((buffer (get-buffer-create (format " *nnml overview %s*" group))))
+ (save-excursion
+ (set-buffer buffer)
+ (set (make-local-variable 'nnml-nov-buffer-file-name)
+ (expand-file-name
+ nnml-nov-file-name
+ (nnmail-group-pathname group nnml-directory)))
+ (erase-buffer)
+ (when (file-exists-p nnml-nov-buffer-file-name)
+ (nnheader-insert-file-contents nnml-nov-buffer-file-name)))
+ buffer))
+
(defun nnml-open-nov (group)
(or (cdr (assoc group nnml-nov-buffer-alist))
- (let ((buffer (get-buffer-create (format " *nnml overview %s*" group))))
- (save-excursion
- (set-buffer buffer)
- (set (make-local-variable 'nnml-nov-buffer-file-name)
- (expand-file-name
- nnml-nov-file-name
- (nnmail-group-pathname group nnml-directory)))
- (erase-buffer)
- (when (file-exists-p nnml-nov-buffer-file-name)
- (nnheader-insert-file-contents nnml-nov-buffer-file-name)))
+ (let ((buffer (nnml-get-nov-buffer group)))
(push (cons group buffer) nnml-nov-buffer-alist)
buffer)))
(narrow-to-region
(goto-char (point-min))
(progn
- (search-forward "\n\n" nil t)
+ (re-search-forward "\n\r?\n" nil t)
(setq chars (- (point-max) (point)))
(max 1 (1- (point)))))
(unless (zerop (buffer-size))
(when (or (not nnml-article-file-alist)
force)
(setq nnml-article-file-alist
- (nnheader-article-to-file-alist nnml-current-directory))))
+ (nnml-current-group-article-to-file-alist))))
+
+(defun nnml-directory-articles (dir)
+ "Return a list of all article files in a directory.
+Use the nov database for that directory if available."
+ (if (or gnus-nov-is-evil nnml-nov-is-evil
+ (not (file-exists-p
+ (expand-file-name nnml-nov-file-name dir))))
+ (nnheader-directory-articles dir)
+ ;; build list from .overview if available
+ ;; We would use nnml-open-nov, except that nnml-nov-buffer-alist is
+ ;; defvoo'd, and we might get called when it hasn't been swapped in.
+ (save-excursion
+ (let ((list nil)
+ art
+ (buffer (nnml-get-nov-buffer nnml-current-group)))
+ (set-buffer buffer)
+ (goto-char (point-min))
+ (while (not (eobp))
+ (setq art (read (current-buffer)))
+ (push art list)
+ (forward-line 1))
+ list))))
+
+(defun nnml-current-group-article-to-file-alist ()
+ "Return an alist of article/file pairs in the current group.
+Use the nov database for the current group if available."
+ (if (or gnus-nov-is-evil
+ nnml-nov-is-evil
+ nnml-filenames-are-evil
+ (not (file-exists-p
+ (expand-file-name nnml-nov-file-name
+ nnml-current-directory))))
+ (nnheader-article-to-file-alist nnml-current-directory)
+ ;; build list from .overview if available
+ (save-excursion
+ (let ((alist nil)
+ art
+ (buffer (nnml-get-nov-buffer nnml-current-group)))
+ (set-buffer buffer)
+ (goto-char (point-min))
+ (while (not (eobp))
+ (setq art (read (current-buffer)))
+ ;; assume file name is unadorned (ie. not compressed etc)
+ (push (cons art (int-to-string art)) alist)
+ (forward-line 1))
+ alist))))
+
+(deffoo nnml-request-set-mark (group actions &optional server)
+ (nnml-possibly-change-directory group server)
+ (unless nnml-marks-is-evil
+ (nnml-open-marks group server)
+ (dolist (action actions)
+ (let ((range (nth 0 action))
+ (what (nth 1 action))
+ (marks (nth 2 action)))
+ (assert (or (eq what 'add) (eq what 'del)) t
+ "Unknown request-set-mark action: %s" what)
+ (dolist (mark marks)
+ (setq nnml-marks (gnus-update-alist-soft
+ mark
+ (funcall (if (eq what 'add) 'gnus-range-add
+ 'gnus-remove-from-range)
+ (cdr (assoc mark nnml-marks)) range)
+ nnml-marks)))))
+ (nnml-save-marks group server))
+ nil)
+
+(deffoo nnml-request-update-info (group info &optional server)
+ (nnml-possibly-change-directory group server)
+ (when (and (not nnml-marks-is-evil) (nnml-marks-changed-p group))
+ (nnheader-message 8 "Updating marks for %s..." group)
+ (nnml-open-marks group server)
+ ;; Update info using `nnml-marks'.
+ (mapcar (lambda (pred)
+ (gnus-info-set-marks
+ info
+ (gnus-update-alist-soft
+ (cdr pred)
+ (cdr (assq (cdr pred) nnml-marks))
+ (gnus-info-marks info))
+ t))
+ gnus-article-mark-lists)
+ (let ((seen (cdr (assq 'read nnml-marks))))
+ (gnus-info-set-read info
+ (if (and (integerp (car seen))
+ (null (cdr seen)))
+ (list (cons (car seen) (car seen)))
+ seen)))
+ (nnheader-message 8 "Updating marks for %s...done" group))
+ info)
+
+(defun nnml-marks-changed-p (group)
+ (let ((file (expand-file-name nnml-marks-file-name
+ (nnmail-group-pathname group nnml-directory))))
+ (if (null (gnus-gethash file nnml-marks-modtime))
+ t ;; never looked at marks file, assume it has changed
+ (not (equal (gnus-gethash file nnml-marks-modtime)
+ (nth 5 (file-attributes file)))))))
+
+(defun nnml-save-marks (group server)
+ (let ((file-name-coding-system nnmail-pathname-coding-system)
+ (file (expand-file-name nnml-marks-file-name
+ (nnmail-group-pathname group nnml-directory))))
+ (condition-case err
+ (progn
+ (nnml-possibly-create-directory group)
+ (with-temp-file file
+ (erase-buffer)
+ (gnus-prin1 nnml-marks)
+ (insert "\n"))
+ (gnus-sethash file
+ (nth 5 (file-attributes file))
+ nnml-marks-modtime))
+ (error (or (gnus-yes-or-no-p
+ (format "Could not write to %s (%s). Continue? " file err))
+ (error "Cannot write to %s (%s)" err))))))
+
+(defun nnml-open-marks (group server)
+ (let ((file (expand-file-name
+ nnml-marks-file-name
+ (nnmail-group-pathname group nnml-directory))))
+ (if (file-exists-p file)
+ (condition-case err
+ (with-temp-buffer
+ (gnus-sethash file (nth 5 (file-attributes file))
+ nnml-marks-modtime)
+ (nnheader-insert-file-contents file)
+ (setq nnml-marks (read (current-buffer)))
+ (dolist (el gnus-article-unpropagated-mark-lists)
+ (setq nnml-marks (gnus-remassoc el nnml-marks))))
+ (error (or (gnus-yes-or-no-p
+ (format "Error reading nnml marks file %s (%s). Continuing will use marks from .newsrc.eld. Continue? " file err))
+ (error "Cannot read nnml marks file %s (%s)" file err))))
+ ;; User didn't have a .marks file. Probably first time
+ ;; user of the .marks stuff. Bootstrap it from .newsrc.eld.
+ (let ((info (gnus-get-info
+ (gnus-group-prefixed-name
+ group
+ (gnus-server-to-method (format "nnml:%s" server))))))
+ (nnheader-message 7 "Bootstrapping marks for %s..." group)
+ (setq nnml-marks (gnus-info-marks info))
+ (push (cons 'read (gnus-info-read info)) nnml-marks)
+ (dolist (el gnus-article-unpropagated-mark-lists)
+ (setq nnml-marks (gnus-remassoc el nnml-marks)))
+ (nnml-save-marks group server)))))
(provide 'nnml)
;;; nnoo.el --- OO Gnus Backends
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
"The same as `defvar', only takes list of variables to MAP to."
`(prog1
,(if doc
- `(defvar ,var ,init ,doc)
+ `(defvar ,var ,init ,(concat doc "\n\nThis is a Gnus server variable. See Info node `(gnus)Select Methods'."))
`(defvar ,var ,init))
(nnoo-define ',var ',map)))
(put 'defvoo 'lisp-indent-function 2)
(provide 'nnoo)
-;;; nnoo.el ends here.
+;;; nnoo.el ends here
(eval-when-compile (require 'cl))
+(require 'gnus)
(require 'nnoo)
(require 'nnmail)
(require 'message)
(require 'mm-util)
(require 'gnus-util)
(require 'time-date)
+(require 'rfc2231)
+(require 'mm-url)
(eval-when-compile
(ignore-errors
- (require 'xml)
- (require 'w3)
- (require 'w3-forms)
- (require 'nnweb)))
+ (require 'xml)))
;; Report failure to find w3 at load time if appropriate.
-(eval '(progn
- (require 'xml)
- (require 'w3)
- (require 'w3-forms)
- (require 'nnweb)))
+(eval '(require 'xml))
(nnoo-declare nnrss)
(defvar nnrss-group-alist
'(("MacWeek"
- "http://macweek.zdnet.com/macweek.xml")
+ "http://macweek.zdnet.com/macweek.xml"
+ "The Macintosh news authority.")
("Linux.Weekly.News"
"http://lwn.net/headlines/rss")
("Motley.Fool"
("Slashdot"
"http://www.slashdot.com/slashdot.rdf")
("CNN"
- "http://www.cnn.com/cnn.rss")
+ "http://www.cnn.com/cnn.rss"
+ "The world's news leader.")
("FreshMeat"
- "http://freshmeat.net/backend/fm.rdf")
+ "http://freshmeat.net/backend/fm-releases.rdf"
+ "The one-stop-shop for all your Linux software needs.")
("The.Guardian.newspaper"
- "http://www.guardianunlimited.co.uk/rss/1,,,00.xml")
+ "http://www.guardianunlimited.co.uk/rss/1,,,00.xml"
+ "Intelligent news and comment throughout the day from The Guardian newspaper.")
("MonkeyFist.rdf"
- "http://monkeyfist.com/rdf.php3")
+ "http://monkeyfist.com/rdf.php3"
+ "News and opinion on politics, technology, and eclectic miscellany.")
("NewsForge"
"http://www.newsforge.com/newsforge.rss")
("Reuters.Health"
- "http://www.reutershealth.com/eline.rss")
+ "http://www.reutershealth.com/eline.rss"
+ "Consumer-oriented health-related news stories.")
("Salon"
"http://www.salon.com/feed/RDF/salon_use.rdf")
("Wired"
("ITN"
"http://www.itn.co.uk/itn.rdf")
("Meerkat"
- "http://www.oreillynet.com/meerkat/?_fl=rss10")
+ "http://www.oreillynet.com/meerkat/?_fl=rss10"
+ "An Open Wire Service")
("MonkeyFist"
- "http://monkeyfist.com/rss1.php3")
+ "http://monkeyfist.com/rss1.php3"
+ "News and opinion on politics, technology, and eclectic miscellany.")
("Reuters.Health.rdf"
- "http://www.reutershealth.com/eline.rdf")))
+ "http://www.reutershealth.com/eline.rdf"
+ "Consumer-oriented health-related news stories.")
+;;("4xt" "http://4xt.org/news/general.rss10" "Resources for XT users.")
+ ("Aaronland" "http://aaronland.net/xml/abhb.rdf" "A boy and his basement.")
+ ("Art of the Mix" "http://www.artofthemix.org/xml/rss.asp" "A website devoted to the art of making mixed tapes and cds.")
+ ("Dave Beckett's RDF Resource Guide" "http://www.ilrt.bristol.ac.uk/discovery/rdf/resources/rss.rdf" "A comprehensive guide to resources about RDF.")
+ ("David Chess" "http://www.davidchess.com/words/log.rss" "Mostly-daily musings on philosophy, children, culture, technology, the emergence of life from matter, chocolate, Nomic, and all that sort of thing.")
+;;("Dublin Core Metadata Intitiative" "http://www.dublincore.org/news.rss" "Latest news from DCMI.")
+ ("Figby Articles" "http://www.figby.com/index-rss.php" "A weblog with daily stories about technology, books and publishing, privacy, science, and occasional humor.")
+;;("Figby News" "http://www.figby.com/news.php" "Categorized RSS feeds from various sources.")
+ ("Figby Quickies" "http://www.figby.com/quickies-rss.php" "Quick commented links to other sites from Figby.com.")
+ ("Flutterby!" "http://www.flutterby.com/main.rdf" "News and views from Dan Lyke.")
+ ("Groovelog" "http://groovelog.agora.co.uk/groove+log/groovelog.nsf/today.rss.xml" "The open-access groove users' weblog.")
+;;("Groovelog.rss10" "http://groovelog.agora.co.uk/groove+log/groovelog.nsf/today.rss10.xml" "The open-access groove users' weblog.")
+ ("Hit or Miss" "http://hit-or-miss.org/rss/" "Daily weblog and journal.")
+;;("Internet.com Feeds" "http://www.webreference.com/services/news/" "News from ")
+ ("Larkfarm News" "http://www.larkfarm.com/Larkfarm.rdf" "Mike Gunderloy's web site.")
+ ("Latest RFCs" "http://x42.com/rss/rfc.rss")
+ ("Linux Today" "http://linuxtoday.com/backend/biglt.rss")
+ ("Linux Today.rdf" "http://linuxtoday.com/backend/my-netscape10.rdf")
+ ("More Like This WebLog" "http://www.whump.com/moreLikeThis/RSS" "Because the more you know, the more jokes you get.")
+ ("Motivational Quotes of the Day" "http://www.quotationspage.com/data/mqotd.rss" "Four motivational quotations each day from the Quotations Page.")
+;;("My Netscape Network" "http://www.dmoz.org/Netscape/My_Netscape_Network/")
+ ;;("My UserLand" "http://my.userland.com/choose")
+ ("Network World Fusion NetFlash" "http://www.nwfusion.com/netflash.rss" "Daily breaking news about networking products, technologies and services.")
+;;("News Feeds" "http://newsfeeds.manilasites.com/" "Jeff Barr highlights high quality RSS feeds.")
+ ;;("News Is Free Export" "http://www.newsisfree.com/export.php3")
+ ("News Is Free" "http://www.newsisfree.com/news.rdf.php3")
+;;("News is Free XML Export" "http://www.newsisfree.com/ocs/directory.xml")
+ ("O'Reilly Network Articles" "http://www.oreillynet.com/cs/rss/query/q/260?x-ver=1.0")
+ ("Quotes of the Day" "http://www.quotationspage.com/data/qotd.rss" "Four humorous quotations each day from the Quotations Page.")
+ ("RDF Interest Group" "http://ilrt.org/discovery/rdf-dev/roads/cgi-bin/desire/ig2rss?list=www-rdf-interest" "An experimental channel scraped from the RDF Interest Group mail archives.")
+ ("RDF Logic List" "http://ilrt.org/discovery/rdf-dev/roads/cgi-bin/desire/ig2rss?list=www-rdf-logic" "An experimental channel scraped from the RDF Logic mail archives.")
+ ("RSS Info" "http://www.blogspace.com/rss/rss10" "News and information on the RSS format")
+;;("RSS-DEV listing" "http://www.egroups.com/links/rss-dev/Feeds_000966335046/" "A listing of RSS files from the RSS-DEV list.")
+ ("Semantic Web List" "http://ilrt.org/discovery/rdf-dev/roads/cgi-bin/desire/ig2rss?list=semantic-web" "An experimental channel scraped from the W3C's Semantic Web mail archives.")
+;;("Sherch!" "http://www.sherch.com/~pldms/cgi-bin/sherch.pl" "Sherlock for the rest of us.")
+;;("Street Fusion Archived Financial Webcasts" "http://partners.streetfusion.com/rdf/archive.rdf")
+;;("Street Fusion Upcoming Financial Webcasts" "http://partners.streetfusion.com/rdf/live.rdf")
+;;("TNL.net newsletter" "http://www.tnl.net/newsletter/channel100.asp" "A newsletter about Internet technology and issues.")
+ ("W3C" "http://www.w3.org/2000/08/w3c-synd/home.rss" "The latest news at the World Wide Web Consortium.")
+;;("XML News: RSS Live Content" "http://www.xmlnews.org/RSS/content.html" "A listing of well-known RSS feeds.")
+ ("|fr| XMLfr" "http://xmlfr.org/actualites/general.rss10"
+ "French speaking portal site dedicated to XML.")
+ ("XMLhack" "http://xmlhack.com/rss10.php"
+ "Developer news from the XML community.")
+ ("The Register"
+ "http://www.theregister.co.uk/tonys/slashdot.rdf"
+ "The Register -- Biting the hand that feeds IT.")
+ ("|de| Heise-Ticker"
+ "http://www.heise.de/newsticker/heise.rdf"
+ "German news ticker about technology.")
+ ("|de| Telepolis News"
+ "http://www.heise.de/tp/news.rdf"
+ "German background news about technology.")
+ ("Kuro5hin"
+ "http://www.kuro5hin.org/backend.rdf"
+ "Technology and culture, from the trenches.")
+ ("JabberCentral"
+ "http://www.jabbercentral.com/rss.php"
+ "News around the Jabber instant messaging system.")))
(defvar nnrss-use-local nil)
+(defvar nnrss-description-field 'X-Gnus-Description
+ "Field name used for DESCRIPTION.
+To use the description in headers, put this name into `nnmail-extra-headers'.")
+
+(defvar nnrss-url-field 'X-Gnus-Url
+ "Field name used for URL.
+To use the description in headers, put this name into `nnmail-extra-headers'.")
+
(nnoo-define-basics nnrss)
;;; Interface functions
(if (setq e (assq article nnrss-group-data))
(insert (number-to-string (car e)) "\t" ;; number
(if (nth 3 e)
- (nnrss-string-as-multibyte (nth 3 e)) "")
+ (nnrss-format-string (nth 3 e)) "")
"\t" ;; subject
(if (nth 4 e)
- (nnrss-string-as-multibyte (nth 4 e)) "")
+ (nnrss-format-string (nth 4 e))
+ "(nobody)")
"\t" ;;from
(or (nth 5 e) "")
"\t" ;; date
(format "<%d@%s.nnrss>" (car e) group)
"\t" ;; id
"\t" ;; refs
- "0" "\t" ;; chars
- "0" "\t" ;; lines
+ "-1" "\t" ;; chars
+ "-1" "\t" ;; lines
+ "" "\t" ;; Xref
+ (if (and (nth 6 e)
+ (memq nnrss-description-field
+ nnmail-extra-headers))
+ (concat (symbol-name nnrss-description-field)
+ ": "
+ (nnrss-format-string (nth 6 e))
+ "\t")
+ "")
+ (if (and (nth 2 e)
+ (memq nnrss-url-field
+ nnmail-extra-headers))
+ (concat (symbol-name nnrss-url-field)
+ ": "
+ (nnrss-format-string (nth 2 e))
+ "\t")
+ "")
"\n")))))
'nov)
(with-current-buffer nntp-server-buffer
(erase-buffer)
(goto-char (point-min))
+ (if group
+ (insert "Newsgroups: " group "\n"))
(if (nth 3 e)
- (insert "Subject: " (nnrss-string-as-multibyte (nth 3 e)) "\n"))
+ (insert "Subject: " (nnrss-format-string (nth 3 e)) "\n"))
(if (nth 4 e)
- (insert "From: " (nnrss-string-as-multibyte (nth 4 e)) "\n"))
+ (insert "From: " (nnrss-format-string (nth 4 e)) "\n"))
(if (nth 5 e)
- (insert "Date: " (nnrss-string-as-multibyte (nth 5 e)) "\n"))
+ (insert "Date: " (nnrss-format-string (nth 5 e)) "\n"))
(insert "Message-ID: " (format "<%d@%s.nnrss>" (car e) group) "\n")
(insert "\n")
(if (nth 6 e)
(let ((point (point)))
- (insert (nnrss-string-as-multibyte (nth 6 e)) "\n\n")
+ (insert (nnrss-string-as-multibyte (nth 6 e)))
+ (goto-char point)
+ (while (search-forward "\n" nil t)
+ (delete-char -1))
+ (goto-char (point-max))
+ (insert "\n\n")
(fill-region point (point))))
(if (nth 2 e)
(insert (nth 2 e) "\n")))))
t)
(deffoo nnrss-open-server (server &optional defs connectionless)
+ (nnrss-read-server-data server)
(nnoo-change-server 'nnrss server defs)
t)
(deffoo nnrss-request-expire-articles
(articles group &optional server force)
(nnrss-possibly-change-group group server)
- (let (e changed days)
+ (let (e days not-expirable changed)
(dolist (art articles)
- (when (setq e (assq art nnrss-group-data))
- (if (nnmail-expired-article-p
- group
- (if (listp (setq days (nth 1 e))) days (days-to-time days))
- force)
+ (if (and (setq e (assq art nnrss-group-data))
+ (nnmail-expired-article-p
+ group
+ (if (listp (setq days (nth 1 e))) days
+ (days-to-time (- days (time-to-days '(0 0)))))
+ force))
(setq nnrss-group-data (delq e nnrss-group-data)
- changed t))))
+ changed t)
+ (push art not-expirable)))
(if changed
- (nnrss-save-group-data group server))))
+ (nnrss-save-group-data group server))
+ not-expirable))
(deffoo nnrss-request-delete-group (group &optional force server)
(nnrss-possibly-change-group group server)
(setq nnrss-server-data
(delq (assoc group nnrss-server-data) nnrss-server-data))
(nnrss-save-server-data server)
- (let ((file (expand-file-name (concat group (and server
- (not (equal server ""))
- "-")
- server ".el") nnrss-directory)))
- (delete-file file))
+ (let ((file (expand-file-name
+ (nnrss-translate-file-chars
+ (concat group (and server
+ (not (equal server ""))
+ "-")
+ server ".el")) nnrss-directory)))
+ (ignore-errors
+ (delete-file file)))
+ t)
+
+(deffoo nnrss-request-list-newsgroups (&optional server)
+ (nnrss-possibly-change-group nil server)
+ (save-excursion
+ (set-buffer nntp-server-buffer)
+ (erase-buffer)
+ (dolist (elem nnrss-group-alist)
+ (if (third elem)
+ (insert (car elem) "\t" (third elem) "\n"))))
t)
(nnoo-define-skeleton nnrss)
(defun nnrss-possibly-change-group (&optional group server)
(when (and server
(not (nnrss-server-opened server)))
- (nnrss-read-server-data server)
(nnrss-open-server server))
(when (and group (not (equal group nnrss-group)))
(nnrss-read-group-data group server)
(setq nnrss-group group)))
+(defvar nnrss-extra-categories '(nnrss-snarf-moreover-categories))
+
(defun nnrss-generate-active ()
+ (if (y-or-n-p "Fetch extra categories? ")
+ (dolist (func nnrss-extra-categories)
+ (funcall func)))
(save-excursion
(set-buffer nntp-server-buffer)
(erase-buffer)
(defun nnrss-read-server-data (server)
(setq nnrss-server-data nil)
- (let ((file (expand-file-name (concat "nnrss" (and server
- (not (equal server ""))
- "-")
- server
- ".el")
- nnrss-directory)))
+ (let ((file (expand-file-name
+ (nnrss-translate-file-chars
+ (concat "nnrss" (and server
+ (not (equal server ""))
+ "-")
+ server
+ ".el"))
+ nnrss-directory)))
(when (file-exists-p file)
(with-temp-buffer
- (let ((coding-system-for-read 'binary))
- (insert-file-contents file))
- (goto-char (point-min))
- (eval-buffer)))))
+ (let ((coding-system-for-read 'binary)
+ emacs-lisp-mode-hook)
+ (insert-file-contents file)
+ (emacs-lisp-mode)
+ (goto-char (point-min))
+ (eval-buffer))))))
(defun nnrss-save-server-data (server)
(gnus-make-directory nnrss-directory)
- (let ((file (expand-file-name (concat "nnrss" (and server
- (not (equal server ""))
- "-")
- server ".el")
- nnrss-directory)))
- (let ((coding-system-for-write 'binary))
+ (let ((file (expand-file-name
+ (nnrss-translate-file-chars
+ (concat "nnrss" (and server
+ (not (equal server ""))
+ "-")
+ server ".el"))
+ nnrss-directory)))
+ (let ((coding-system-for-write 'binary)
+ print-level print-length)
(with-temp-file file
(insert "(setq nnrss-server-data '"
(prin1-to-string nnrss-server-data)
(let ((pair (assoc group nnrss-server-data)))
(setq nnrss-group-max (or (cadr pair) 0))
(setq nnrss-group-min (+ nnrss-group-max 1)))
- (let ((file (expand-file-name (concat group (and server
- (not (equal server ""))
- "-")
- server ".el")
- nnrss-directory)))
+ (let ((file (expand-file-name
+ (nnrss-translate-file-chars
+ (concat group (and server
+ (not (equal server ""))
+ "-")
+ server ".el"))
+ nnrss-directory)))
(when (file-exists-p file)
(with-temp-buffer
- (let ((coding-system-for-read 'binary))
- (insert-file-contents file))
- (goto-char (point-min))
- (eval-buffer))
+ (let ((coding-system-for-read 'binary)
+ emacs-lisp-mode-hook)
+ (insert-file-contents file)
+ (emacs-lisp-mode)
+ (goto-char (point-min))
+ (eval-buffer)))
(dolist (e nnrss-group-data)
(gnus-sethash (nth 2 e) e nnrss-group-hashtb)
(if (and (car e) (> nnrss-group-min (car e)))
(defun nnrss-save-group-data (group server)
(gnus-make-directory nnrss-directory)
- (let ((file (expand-file-name (concat group (and server
- (not (equal server ""))
- "-")
- server ".el")
- nnrss-directory)))
- (let ((coding-system-for-write 'binary))
+ (let ((file (expand-file-name
+ (nnrss-translate-file-chars
+ (concat group (and server
+ (not (equal server ""))
+ "-")
+ server ".el"))
+ nnrss-directory)))
+ (let ((coding-system-for-write 'binary)
+ print-level print-length)
(with-temp-file file
(insert "(setq nnrss-group-data '"
(prin1-to-string nnrss-group-data)
(defun nnrss-no-cache (url)
"")
-;; TODO:: disable cache.
-;;
-;; (defun nnrss-insert-w3 (url)
-;; (require 'url)
-;; (require 'url-cache)
-;; (let ((url-cache-creation-function 'nnrss-no-cache))
-;; (mm-with-unibyte-current-buffer
-;; (nnweb-insert url))))
-
(defun nnrss-insert-w3 (url)
(mm-with-unibyte-current-buffer
- (nnweb-insert url)))
+ (mm-url-insert url)))
(defun nnrss-decode-entities-unibyte-string (string)
(mm-with-unibyte-buffer
(insert string)
- (nnweb-decode-entities)
+ (mm-url-decode-entities-nbsp)
(buffer-substring (point-min) (point-max))))
(defalias 'nnrss-insert 'nnrss-insert-w3)
;;; Snarf functions
(defun nnrss-check-group (group server)
- (let ((w3-html-entities (cons '(nbsp . 32) w3-html-entities))
- file xml subject url extra changed author date)
- (mm-with-unibyte-buffer
- (if (and nnrss-use-local
- (file-exists-p (setq file (expand-file-name
- (concat group ".xml")
- nnrss-directory))))
- (insert-file-contents file)
- (setq url (or (nth 2 (assoc group nnrss-server-data))
- (second (assoc group nnrss-group-alist))))
- (unless url
- (setq url
- (read-string (format "RSS url of %s: " group "http://")))
- (let ((pair (assoc group nnrss-server-data)))
- (if pair
- (setcdr (cdr pair) (list url))
- (push (list group nnrss-group-max url) nnrss-server-data)))
- (setq changed t))
- (nnrss-insert url))
- (goto-char (point-min))
- (while (re-search-forward "\r\n?" nil t)
- (replace-match "\n"))
- (goto-char (point-min))
- (if (re-search-forward "<rdf\\|<rss" nil t)
- (goto-char (match-beginning 0)))
- (setq xml (xml-parse-region (point) (point-max))))
+ (let (file xml subject url extra changed author date)
+ (condition-case err
+ (mm-with-unibyte-buffer
+ (if (and nnrss-use-local
+ (file-exists-p (setq file (expand-file-name
+ (nnrss-translate-file-chars
+ (concat group ".xml"))
+ nnrss-directory))))
+ (insert-file-contents file)
+ (setq url (or (nth 2 (assoc group nnrss-server-data))
+ (second (assoc group nnrss-group-alist))))
+ (unless url
+ (setq url
+ (read-string (format "RSS url of %s: " group "http://")))
+ (let ((pair (assoc group nnrss-server-data)))
+ (if pair
+ (setcdr (cdr pair) (list url))
+ (push (list group nnrss-group-max url) nnrss-server-data)))
+ (setq changed t))
+ (nnrss-insert url))
+ (goto-char (point-min))
+ (while (re-search-forward "\r\n?" nil t)
+ (replace-match "\n"))
+ (goto-char (point-min))
+ (if (re-search-forward "<rdf\\|<rss" nil t)
+ (goto-char (match-beginning 0)))
+ (setq xml (xml-parse-region (point) (point-max))))
+ (error
+ (nnheader-message 1 "Error in group %s: %s" group (cadr err))))
(while (and xml (not (assq 'item xml)))
- (unless (listp (car (setq xml (cddar xml))))
- (setq xml nil)))
- (dolist (item xml)
- (when (and (listp item)
- (eq 'item (car item))
- (setq url (caddr (assq 'link (cddr item))))
- (setq url (nnrss-decode-entities-unibyte-string url))
- (not (gnus-gethash url nnrss-group-hashtb)))
- (setq subject (caddr (assq 'title (cddr item))))
- (setq extra (or (caddr (assq 'description (cddr item)))
- (caddr (assq 'dc:description (cddr item)))))
- (setq author (caddr (assq 'dc:creator (cddr item))))
- (setq date (or (caddr (assq 'dc:date (cddr item)))
- (message-make-date)))
- (push
- (list
- (incf nnrss-group-max)
- (time-to-days (current-time))
- url
- (and subject (nnrss-decode-entities-unibyte-string subject))
- (and author (nnrss-decode-entities-unibyte-string author))
- date
- (and extra (nnrss-decode-entities-unibyte-string extra)))
- nnrss-group-data)
- (gnus-sethash url (car nnrss-group-data) nnrss-group-hashtb)
- (setq changed t)))
+ (setq xml (cddar xml))
+ (while (not (listp (car xml)))
+ (setq xml (cdr xml))))
+ (dolist (item (nreverse xml))
+ (when (and (listp item)
+ (eq 'item (car item))
+ (setq url (nnrss-node-text (assq 'link (cddr item))))
+ (setq url (nnrss-decode-entities-unibyte-string url))
+ (not (gnus-gethash url nnrss-group-hashtb)))
+ (setq subject (nnrss-node-text (assq 'title (cddr item))))
+ (setq extra (or (nnrss-node-text (assq 'description (cddr item)))
+ (nnrss-node-text (assq 'dc:description (cddr item)))))
+ (setq author (nnrss-node-text (assq 'dc:creator (cddr item))))
+ (setq date (or (nnrss-node-text (assq 'dc:date (cddr item)))
+ (message-make-date)))
+ (push
+ (list
+ (incf nnrss-group-max)
+ (current-time)
+ url
+ (and subject (nnrss-decode-entities-unibyte-string subject))
+ (and author (nnrss-decode-entities-unibyte-string author))
+ date
+ (and extra (nnrss-decode-entities-unibyte-string extra)))
+ nnrss-group-data)
+ (gnus-sethash url (car nnrss-group-data) nnrss-group-hashtb)
+ (setq changed t)))
(when changed
- (nnrss-save-group-data group server)
- (let ((pair (assoc group nnrss-server-data)))
- (if pair
- (setcar (cdr pair) nnrss-group-max)
- (push (list group nnrss-group-max) nnrss-server-data)))
- (nnrss-save-server-data server))))
+ (nnrss-save-group-data group server)
+ (let ((pair (assoc group nnrss-server-data)))
+ (if pair
+ (setcar (cdr pair) nnrss-group-max)
+ (push (list group nnrss-group-max) nnrss-server-data)))
+ (nnrss-save-server-data server))))
+
+(defun nnrss-generate-download-script ()
+ "Generate a download script in the current buffer.
+It is useful when `(setq nnrss-use-local t)'."
+ (interactive)
+ (insert "#!/bin/sh\n")
+ (insert "WGET=wget\n")
+ (insert "RSSDIR='" (expand-file-name nnrss-directory) "'\n")
+ (dolist (elem nnrss-server-data)
+ (let ((url (or (nth 2 elem)
+ (second (assoc (car elem) nnrss-group-alist)))))
+ (insert "$WGET -q -O \"$RSSDIR\"/'"
+ (nnrss-translate-file-chars (concat (car elem) ".xml"))
+ "' '" url "'\n"))))
+
+(defun nnrss-translate-file-chars (name)
+ (let ((nnheader-file-name-translation-alist
+ (append nnheader-file-name-translation-alist '((?' . ?_)))))
+ (nnheader-translate-file-chars name)))
+
+(defvar nnrss-moreover-url
+ "http://w.moreover.com/categories/category_list_rss.html"
+ "The url of moreover.com categories.")
+
+(defun nnrss-snarf-moreover-categories ()
+ "Snarf RSS links from moreover.com."
+ (interactive)
+ (let (category name url changed)
+ (with-temp-buffer
+ (nnrss-insert nnrss-moreover-url)
+ (goto-char (point-min))
+ (while (re-search-forward
+ "<A NAME=\"\\([^\"]+\\)\">\\|<A HREF=\"\\(http://[^\"]*moreover\\.com[^\"]+page\\?c=\\([^\"&]+\\)&o=rss\\)" nil t)
+ (if (match-string 1)
+ (setq category (match-string 1))
+ (setq url (match-string 2)
+ name (mm-url-decode-entities-string
+ (rfc2231-decode-encoded-string
+ (match-string 3))))
+ (if category
+ (setq name (concat category "." name)))
+ (unless (assoc name nnrss-server-data)
+ (setq changed t)
+ (push (list name 0 url) nnrss-server-data)))))
+ (if changed
+ (nnrss-save-server-data ""))))
+
+(defun nnrss-format-string (string)
+ (gnus-replace-in-string (nnrss-string-as-multibyte string) " *\n *" " "))
+
+(defun nnrss-node-text (node)
+ (if (and node (listp node))
+ (mapconcat 'nnrss-node-text (cddr node) "")
+ node))
(provide 'nnrss)
(require 'gnus)
(require 'nnmail)
(require 'mm-util)
-(eval-when-compile
- (ignore-errors
- (require 'nnweb)))
-;; Report failure to find w3 at load time if appropriate.
-(eval '(require 'nnweb))
+(require 'mm-url)
(nnoo-declare nnslashdot)
(nnslashdot-possibly-change-server group server)
(condition-case why
(unless gnus-nov-is-evil
- (if nnslashdot-threaded
- (nnslashdot-threaded-retrieve-headers articles group)
- (nnslashdot-sane-retrieve-headers articles group)))
+ (nnslashdot-retrieve-headers-1 articles group))
(search-failed (nnslashdot-lose why))))
-(deffoo nnslashdot-threaded-retrieve-headers (articles group)
- (let ((last (car (last articles)))
- (did nil)
- (start 1)
- (sid (caddr (assoc group nnslashdot-groups)))
- (first-comments t)
- (startats '(1))
- headers article subject score from date lines parent point s)
+(deffoo nnslashdot-retrieve-headers-1 (articles group)
+ (let* ((last (car (last articles)))
+ (start (if nnslashdot-threaded 1 (pop articles)))
+ (entry (assoc group nnslashdot-groups))
+ (sid (nth 2 entry))
+ (first-comments t)
+ headers article subject score from date lines parent point cid
+ s startats changed)
(save-excursion
(set-buffer nnslashdot-buffer)
(let ((case-fold-search t))
(erase-buffer)
(when (= start 1)
- (nnweb-insert (format nnslashdot-article-url
+ (mm-url-insert (format nnslashdot-article-url
(nnslashdot-sid-strip sid)) t)
(goto-char (point-min))
- (search-forward "Posted by ")
- (when (looking-at "<a[^>]+>\\([^<]+\\)")
- (setq from (nnweb-decode-entities-string (match-string 1))))
- (search-forward " on ")
+ (re-search-forward "Posted by[ \t\r\n]+")
+ (when (looking-at "\\(<a[^>]+>\\)?[ \t\r\n]*\\([^<\r\n]+\\)")
+ (setq from (mm-url-decode-entities-string (match-string 2))))
+ (search-forward "on ")
(setq date (nnslashdot-date-to-date
(buffer-substring (point) (1- (search-forward "<")))))
(setq lines (/ (- (point)
1 group from date
(concat "<" (nnslashdot-sid-strip sid) "%1@slashdot>")
"" 0 lines nil nil))
- headers))
- (while (and (setq start (pop startats))
- (< start last))
+ headers)
+ (setq start (if nnslashdot-threaded 2 (pop articles))))
+ (while (and start (<= start last))
(setq point (goto-char (point-max)))
- (nnweb-insert
+ (mm-url-insert
(format nnslashdot-comments-url
(nnslashdot-sid-strip sid)
- nnslashdot-threshold 0 start)
+ nnslashdot-threshold 0 (- start 2))
t)
- (when first-comments
+ (when (and nnslashdot-threaded first-comments)
(setq first-comments nil)
(goto-char (point-max))
(while (re-search-backward "startat=\\([0-9]+\\)" nil t)
(unless (memq s startats)
(push s startats)))
(setq startats (sort startats '<)))
+ (setq article (if (and article (< start article)) article start))
(goto-char point)
(while (re-search-forward
"<a name=\"\\([0-9]+\\)\"><\\(b\\|H4\\)>\\([^<]+\\)</\\(b\\|H4\\)>.*score:\\([^)]+\\))"
nil t)
- (setq article (string-to-number (match-string 1))
+ (setq cid (match-string 1)
subject (match-string 3)
score (match-string 5))
+ (unless (assq article (nth 4 entry))
+ (setcar (nthcdr 4 entry) (cons (cons article cid) (nth 4 entry)))
+ (setq changed t))
(when (string-match "^Re: *" subject)
(setq subject (concat "Re: " (substring subject (match-end 0)))))
- (setq subject (nnweb-decode-entities-string subject))
- (forward-line 1)
+ (setq subject (mm-url-decode-entities-string subject))
+ (search-forward "<BR>")
(if (looking-at
- "by <a[^>]+>\\([^<]+\\)</a>[ \t\n]*.*(\\([^)]+\\))")
+ "by[ \t\n]+<a[^>]+>\\([^<]+\\)</a>[ \t\n]*(\\(<[^>]+>\\)*\\([^<>)]+\\))")
(progn
(goto-char (- (match-end 0) 5))
(setq from (concat
- (nnweb-decode-entities-string (match-string 1))
- " <" (match-string 2) ">")))
+ (mm-url-decode-entities-string (match-string 1))
+ " <" (match-string 3) ">")))
(setq from "")
- (when (looking-at "by \\(.+\\) on ")
+ (when (looking-at "by \\([^<>]*\\) on ")
(goto-char (- (match-end 0) 5))
- (setq from (nnweb-decode-entities-string (match-string 1)))))
+ (setq from (mm-url-decode-entities-string (match-string 1)))))
(search-forward " on ")
(setq date
(nnslashdot-date-to-date
- (buffer-substring (point) (progn (end-of-line) (point)))))
- (setq lines (/ (abs (- (search-forward "<td ")
+ (buffer-substring (point) (progn (skip-chars-forward "^()<>\n\r") (point)))))
+ (setq lines (/ (abs (- (search-forward "<td")
(search-forward "</td>")))
70))
- (forward-line 4)
- (setq parent
- (if (looking-at ".*cid=\\([0-9]+\\)")
- (match-string 1)
- nil))
- (setq did t)
+ (if (not
+ (re-search-forward ".*cid=\\([0-9]+\\)\">Parent</A>" nil t))
+ (setq parent nil)
+ (setq parent (match-string 1))
+ (when (string= parent "0")
+ (setq parent nil)))
(push
(cons
- (1+ article)
+ article
(make-full-mail-header
- (1+ article)
+ article
(concat subject " (" score ")")
from date
- (concat "<" (nnslashdot-sid-strip sid) "%"
- (number-to-string (1+ article))
- "@slashdot>")
+ (concat "<" (nnslashdot-sid-strip sid) "%" cid "@slashdot>")
(if parent
- (concat "<" (nnslashdot-sid-strip sid) "%"
- (number-to-string (1+ (string-to-number parent)))
- "@slashdot>")
+ (concat "<" (nnslashdot-sid-strip sid) "%"
+ parent "@slashdot>")
"")
0 lines nil nil))
- headers)))))
+ headers)
+ (while (and articles (<= (car articles) article))
+ (pop articles))
+ (setq article (1+ article)))
+ (if nnslashdot-threaded
+ (progn
+ (setq start (pop startats))
+ (if start (setq start (+ start 2))))
+ (setq start (pop articles))))))
+ (if changed (nnslashdot-write-groups))
(setq nnslashdot-headers (sort headers 'car-less-than-car))
(save-excursion
(set-buffer nntp-server-buffer)
(nnheader-insert-nov (cdr header)))))
'nov))
-(deffoo nnslashdot-sane-retrieve-headers (articles group)
- (let ((last (car (last articles)))
- (did nil)
- (start (max (1- (car articles)) 1))
- (sid (caddr (assoc group nnslashdot-groups)))
- headers article subject score from date lines parent point)
- (save-excursion
- (set-buffer nnslashdot-buffer)
- (erase-buffer)
- (when (= start 1)
- (nnweb-insert (format nnslashdot-article-url
- (nnslashdot-sid-strip sid)) t)
- (goto-char (point-min))
- (search-forward "Posted by ")
- (when (looking-at "<a[^>]+>\\([^<]+\\)")
- (setq from (nnweb-decode-entities-string (match-string 1))))
- (search-forward " on ")
- (setq date (nnslashdot-date-to-date
- (buffer-substring (point) (1- (search-forward "<")))))
- (forward-line 2)
- (setq lines (count-lines (point)
- (re-search-forward
- "A href=\"\\(http://slashdot.org\\)?/article")))
- (push
- (cons
- 1
- (make-full-mail-header
- 1 group from date (concat "<" (nnslashdot-sid-strip sid)
- "%1@slashdot>")
- "" 0 lines nil nil))
- headers))
- (while (or (not article)
- (and did
- (< article last)))
- (when article
- (setq start (1+ article)))
- (setq point (goto-char (point-max)))
- (nnweb-insert
- (format nnslashdot-comments-url (nnslashdot-sid-strip sid)
- nnslashdot-threshold 4 start)
- t)
- (goto-char point)
- (while (re-search-forward
- "<a name=\"\\([0-9]+\\)\"><\\(b\\|H4\\)>\\([^<]+\\)</\\(b\\|H4\\)>.*score:\\([^)]+\\))"
- nil t)
- (setq article (string-to-number (match-string 1))
- subject (match-string 3)
- score (match-string 5))
- (when (string-match "^Re: *" subject)
- (setq subject (concat "Re: " (substring subject (match-end 0)))))
- (setq subject (nnweb-decode-entities-string subject))
- (forward-line 1)
- (if (looking-at
- "by <a[^>]+>\\([^<]+\\)</a>[ \t\n]*.*(\\([^)]+\\))")
- (progn
- (goto-char (- (match-end 0) 5))
- (setq from (concat
- (nnweb-decode-entities-string (match-string 1))
- " <" (match-string 2) ">")))
- (setq from "")
- (when (looking-at "by \\(.+\\) on ")
- (goto-char (- (match-end 0) 5))
- (setq from (nnweb-decode-entities-string (match-string 1)))))
- (search-forward " on ")
- (setq date
- (nnslashdot-date-to-date
- (buffer-substring (point) (progn (end-of-line) (point)))))
- (setq lines (/ (abs (- (search-forward "<td ")
- (search-forward "</td>")))
- 70))
- (forward-line 2)
- (setq parent
- (if (looking-at ".*cid=\\([0-9]+\\)")
- (match-string 1)
- nil))
- (setq did t)
- (push
- (cons
- (1+ article)
- (make-full-mail-header
- (1+ article) (concat subject " (" score ")")
- from date
- (concat "<" (nnslashdot-sid-strip sid) "%"
- (number-to-string (1+ article))
- "@slashdot>")
- (if parent
- (concat "<" (nnslashdot-sid-strip sid) "%"
- (number-to-string (1+ (string-to-number parent)))
- "@slashdot>")
- "")
- 0 lines nil nil))
- headers))))
- (setq nnslashdot-headers
- (sort headers (lambda (s1 s2) (< (car s1) (car s2)))))
- (save-excursion
- (set-buffer nntp-server-buffer)
- (erase-buffer)
- (mm-with-unibyte-current-buffer
- (dolist (header nnslashdot-headers)
- (nnheader-insert-nov (cdr header)))))
- 'nov))
-
(deffoo nnslashdot-request-group (group &optional server dont-check)
(nnslashdot-possibly-change-server nil server)
(let ((elem (assoc group nnslashdot-groups)))
(deffoo nnslashdot-request-article (article &optional group server buffer)
(nnslashdot-possibly-change-server group server)
- (let (contents)
+ (let (contents cid)
(condition-case why
(save-excursion
(set-buffer nnslashdot-buffer)
(goto-char (point-min))
(when (and (stringp article)
(string-match "%\\([0-9]+\\)@" article))
- (setq article (string-to-number (match-string 1 article))))
+ (setq cid (match-string 1 article))
+ (let ((map (nth 4 (assoc group nnslashdot-groups))))
+ (while map
+ (if (equal (cdar map) cid)
+ (setq article (caar map)
+ map nil)
+ (setq map (cdr map))))))
(when (numberp article)
(if (= article 1)
(progn
- (re-search-forward "Posted by *<[^>]+>[^>]*<[^>]+> *on ")
+ (re-search-forward
+ "Posted by")
(search-forward "<BR>")
(setq contents
(buffer-substring
(point)
(progn
(re-search-forward
- "<p>.*A href=\"\\(http://slashdot.org\\)?/article")
+ "< [ \t\r\n]*<A HREF=\"\\(\\(http:\\)?//slashdot\\.org\\)?/article")
(match-beginning 0)))))
- (search-forward (format "<a name=\"%d\">" (1- article)))
+ (setq cid (cdr (assq article
+ (nth 4 (assoc group nnslashdot-groups)))))
+ (search-forward (format "<a name=\"%s\">" cid))
(setq contents
(buffer-substring
- (re-search-forward "<td[^>]+>")
+ (re-search-forward "<td[^>]*>")
(search-forward "</td>")))))))
(search-failed (nnslashdot-lose why)))
(let ((number 0)
sid elem description articles gname)
(condition-case why
- ;; First we do the Ultramode to get info on all the latest groups.
+ ;; First we do the Ultramode to get info on all the latest groups.
(progn
(mm-with-unibyte-buffer
- (nnweb-insert nnslashdot-backslash-url t)
+ (mm-url-insert nnslashdot-backslash-url t)
(goto-char (point-min))
(while (search-forward "<story>" nil t)
(narrow-to-region (point) (search-forward "</story>"))
(goto-char (point-min))
(re-search-forward "<title>\\([^<]+\\)</title>")
(setq description
- (nnweb-decode-entities-string (match-string 1)))
+ (mm-url-decode-entities-string (match-string 1)))
(re-search-forward "<url>\\([^<]+\\)</url>")
(setq sid (match-string 1))
(string-match "sid=\\([0-9/]+\\)\\(.shtml\\|$\\)" sid)
(setq gname (concat description " (" sid ")"))
(if (setq elem (assoc gname nnslashdot-groups))
(setcar (cdr elem) articles)
- (push (list gname articles sid) nnslashdot-groups))
+ (push (list gname articles sid (current-time) nil)
+ nnslashdot-groups))
(goto-char (point-max))
(widen)))
;; Then do the older groups.
(while (> (- nnslashdot-group-number number) 0)
(mm-with-unibyte-buffer
(let ((case-fold-search t))
- (nnweb-insert (format nnslashdot-active-url number) t)
+ (mm-url-insert (format nnslashdot-active-url number) t)
(goto-char (point-min))
(while (re-search-forward
"article.pl\\?sid=\\([^&]+\\).*<b>\\([^<]+\\)</b>"
nil t)
(setq sid (match-string 1)
description
- (nnweb-decode-entities-string (match-string 2)))
+ (mm-url-decode-entities-string (match-string 2)))
(forward-line 1)
(when (re-search-forward "<b>\\([0-9]+\\)</b>" nil t)
(setq articles (string-to-number (match-string 1))))
(setq gname (concat description " (" sid ")"))
(if (setq elem (assoc gname nnslashdot-groups))
(setcar (cdr elem) articles)
- (push (list gname articles sid) nnslashdot-groups)))))
+ (push (list gname articles sid (current-time) nil)
+ nnslashdot-groups)))))
(incf number 30)))
(search-failed (nnslashdot-lose why)))
(nnslashdot-write-groups)
(message-goto-body)
(setq body (buffer-substring (point) (point-max)))
(erase-buffer)
- (nnweb-fetch-form
+ (mm-url-fetch-form
"http://slashdot.org/comments.pl"
`(("sid" . ,sid)
("pid" . ,pid)
(setq nnslashdot-headers nil
nnslashdot-groups nil))
+(deffoo nnslashdot-request-expire-articles
+ (articles group &optional server force)
+ (nnslashdot-possibly-change-server group server)
+ (let ((item (assoc group nnslashdot-groups)))
+ (when item
+ (if (fourth item)
+ (when (and (>= (length articles) (cadr item)) ;; All are expirable.
+ (nnmail-expired-article-p
+ group
+ (fourth item)
+ force))
+ (setq nnslashdot-groups (delq item nnslashdot-groups))
+ (nnslashdot-write-groups)
+ (setq articles nil)) ;; all expired.
+ (setcdr (cddr item) (list (current-time)))
+ (nnslashdot-write-groups))))
+ articles)
+
(nnoo-define-skeleton nnslashdot)
;;; Internal functions
(unless nnslashdot-groups
(nnslashdot-read-groups)))
+(defun nnslashdot-make-tuple (tuple n)
+ (prog1
+ tuple
+ (while (> n 1)
+ (unless (cdr tuple)
+ (setcdr tuple (list nil)))
+ (setq tuple (cdr tuple)
+ n (1- n)))))
+
(defun nnslashdot-read-groups ()
(let ((file (expand-file-name "groups" nnslashdot-directory)))
(when (file-exists-p file)
(mm-with-unibyte-buffer
(insert-file-contents file)
(goto-char (point-min))
- (setq nnslashdot-groups (read (current-buffer)))))))
+ (setq nnslashdot-groups (read (current-buffer))))
+ (if (and nnslashdot-groups (< (length (car nnslashdot-groups)) 5))
+ (let ((groups nnslashdot-groups))
+ (while groups
+ (nnslashdot-make-tuple (car groups) 5)
+ (setq groups (cdr groups))))))))
(defun nnslashdot-write-groups ()
(with-temp-file (expand-file-name "groups" nnslashdot-directory)
- (prin1 nnslashdot-groups (current-buffer))))
+ (gnus-prin1 nnslashdot-groups)))
(defun nnslashdot-init (server)
"Initialize buffers and such."
(setq nnslashdot-buffer
(save-excursion
(nnheader-set-temp-buffer
- (format " *nnslashdot %s*" server))))))
+ (format " *nnslashdot %s*" server))))
+ (push nnslashdot-buffer gnus-buffers)))
(defun nnslashdot-date-to-date (sdate)
(condition-case err
(defun nnslashdot-lose (why)
(error "Slashdot HTML has changed; please get a new version of nnslashdot"))
-;(defun nnslashdot-sid-strip (sid)
-; (if (string-match "^00/" sid)
-; (substring sid (match-end 0))
-; sid))
-
(defalias 'nnslashdot-sid-strip 'identity)
(provide 'nnslashdot)
;;; nnsoup.el --- SOUP access for Gnus
-;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
(nth 1 (nnsoup-article-to-area
article nnsoup-current-group))))))
(cond ((= kind ?m) 'mail)
- ((= kind ?n) 'news)
+ ((= kind ?n) 'news)
(t 'unknown)))))
(deffoo nnsoup-close-group (group &optional server)
(and areas (car areas))))
(defvar nnsoup-old-functions
- (list message-send-mail-function message-send-news-function))
+ (list message-send-mail-real-function message-send-news-function))
;;;###autoload
(defun nnsoup-set-variables ()
"Use the SOUP methods for posting news and mailing mail."
(interactive)
(setq message-send-news-function 'nnsoup-request-post)
- (setq message-send-mail-function 'nnsoup-request-mail))
+ (setq message-send-mail-real-function 'nnsoup-request-mail))
;;;###autoload
(defun nnsoup-revert-variables ()
"Revert posting and mailing methods to the standard Emacs methods."
(interactive)
- (setq message-send-mail-function (car nnsoup-old-functions))
+ (setq message-send-mail-real-function (car nnsoup-old-functions))
(setq message-send-news-function (cadr nnsoup-old-functions)))
(defun nnsoup-store-reply (kind)
(defvoo nnspool-nov-directory (concat nnspool-spool-directory "over.view/")
"Local news nov directory.")
-(defvoo nnspool-lib-dir
+(defvoo nnspool-lib-dir
(if (file-exists-p "/usr/lib/news/active")
"/usr/lib/news/"
"/var/lib/news/")
(defvoo nntp-open-connection-function 'nntp-open-network-stream
"*Function used for connecting to a remote system.
-It will be called with the buffer to output in.
+It will be called with the buffer to output in as argument.
-Two pre-made functions are `nntp-open-network-stream', which is the
-default, and simply connects to some port or other on the remote
-system (see nntp-port-number). The other are `nntp-open-rlogin',
-which does an rlogin on the remote system, and then does a telnet to
-the NNTP server available there (see nntp-rlogin-parameters) and
-`nntp-open-telnet' which telnets to a remote system, logs in and does
-the same.")
+Currently, five such functions are provided (please refer to their
+respective doc string for more information), three of them establishing
+direct connections to the nntp server, and two of them using an indirect
+host.
-(defvoo nntp-rlogin-program "rsh"
- "*Program used to log in on remote machines.
-The default is \"rsh\", but \"ssh\" is a popular alternative.")
+Direct connections:
+- `nntp-open-network-stream' (the default),
+- `nntp-open-ssl-stream',
+- `nntp-open-telnet-stream'.
-(defvoo nntp-rlogin-parameters '("telnet" "-8" "${NNTPSERVER:=news}" "nntp")
- "*Parameters to `nntp-open-rlogin'.
-That function may be used as `nntp-open-connection-function'. In that
-case, this list will be used as the parameter list given to rsh.")
+Indirect connections:
+- `nntp-open-via-rlogin-and-telnet',
+- `nntp-open-via-telnet-and-telnet'.")
-(defvoo nntp-rlogin-user-name nil
- "*User name on remote system when using the rlogin connect method.")
+(defvoo nntp-pre-command nil
+ "*Pre-command to use with the various nntp-open-via-* methods.
+This is where you would put \"runsocks\" or stuff like that.")
-(defvoo nntp-telnet-parameters
- '("exec" "telnet" "-8" "${NNTPSERVER:=news}" "nntp")
- "*Parameters to `nntp-open-telnet'.
-That function may be used as `nntp-open-connection-function'. In that
-case, this list will be executed as a command after logging in
-via telnet.")
+(defvoo nntp-telnet-command "telnet"
+ "*Telnet command used to connect to the nntp server.
+This command is used by the various nntp-open-via-* methods.")
-(defvoo nntp-telnet-user-name nil
- "User name to log in via telnet with.")
+(defvoo nntp-telnet-switches '("-8")
+ "*Switches given to the telnet command `nntp-telnet-command'.")
-(defvoo nntp-telnet-passwd nil
- "Password to use to log in via telnet with.")
+(defvoo nntp-end-of-line "\r\n"
+ "*String to use on the end of lines when talking to the NNTP server.
+This is \"\\r\\n\" by default, but should be \"\\n\" when
+using and indirect connection method (nntp-open-via-*).")
-(defvoo nntp-open-telnet-envuser nil
- "*If non-nil, telnet session (client and server both) will support the ENVIRON option and not prompt for login name.")
+(defvoo nntp-via-rlogin-command "rsh"
+ "*Rlogin command used to connect to an intermediate host.
+This command is used by the `nntp-open-via-rlogin-and-telnet' method.
+The default is \"rsh\", but \"ssh\" is a popular alternative.")
-(defvoo nntp-telnet-shell-prompt "bash\\|\$ *\r?$\\|> *\r?"
- "*Regular expression to match the shell prompt on the remote machine.")
+(defvoo nntp-via-telnet-command "telnet"
+ "*Telnet command used to connect to an intermediate host.
+This command is used by the `nntp-open-via-telnet-and-telnet' method.")
-(defvoo nntp-telnet-command "telnet"
- "Command used to start telnet.")
+(defvoo nntp-via-telnet-switches '("-8")
+ "*Switches given to the telnet command `nntp-via-telnet-command'.")
-(defvoo nntp-telnet-switches '("-8")
- "Switches given to the telnet command.")
+(defvoo nntp-via-user-name nil
+ "*User name to log in on an intermediate host with.
+This variable is used by the `nntp-open-via-telnet-and-telnet' method.")
-(defvoo nntp-end-of-line "\r\n"
- "String to use on the end of lines when talking to the NNTP server.
-This is \"\\r\\n\" by default, but should be \"\\n\" when
-using rlogin or telnet to communicate with the server.")
+(defvoo nntp-via-user-password nil
+ "*Password to use to log in on an intermediate host with.
+This variable is used by the `nntp-open-via-telnet-and-telnet' method.")
+
+(defvoo nntp-via-address nil
+ "*Address of an intermediate host to connect to.
+This variable is used by the `nntp-open-via-rlogin-and-telnet' and
+`nntp-open-via-telnet-and-telnet' methods.")
+
+(defvoo nntp-via-envuser nil
+ "*Whether both telnet client and server support the ENVIRON option.
+If non-nil, there will be no prompt for a login name.")
+
+(defvoo nntp-via-shell-prompt "bash\\|\$ *\r?$\\|> *\r?"
+ "*Regular expression to match the shell prompt on an intermediate host.
+This variable is used by the `nntp-open-via-telnet-and-telnet' method.")
(defvoo nntp-large-newsgroup 50
"*The number of the articles which indicates a large newsgroup.
If this variable is nil, which is the default, no timers are set.
NOTE: This variable is never seen to work in Emacs 20 and XEmacs 21.")
+(defvoo nntp-prepare-post-hook nil
+ "*Hook run just before posting an article. It is supposed to be used
+to insert Cancel-Lock headers.")
+
;;; Internal variables.
(defvar nntp-record-commands nil
(memq (process-status process) '(open run)))
(when (looking-at "480")
(nntp-handle-authinfo process))
+ (when (looking-at "^.*\n")
+ (delete-region (point) (progn (forward-line 1) (point))))
(nntp-accept-process-output process)
(goto-char (point-min)))
(prog1
(nnheader-report 'nntp "Server closed connection"))
(t
(goto-char (point-max))
- (let ((limit (point-min)))
+ (let ((limit (point-min))
+ response)
(while (not (re-search-backward wait-for limit t))
(nntp-accept-process-output process)
;; We assume that whatever we wait for is less than 1000
;; characters long.
(setq limit (max (- (point-max) 1000) (point-min)))
- (goto-char (point-max))))
+ (goto-char (point-max)))
+ (setq response (match-string 0))
+ (with-current-buffer nntp-server-buffer
+ (setq nntp-process-response response)))
(nntp-decode-text (not decode))
(unless discard
(save-excursion
- (set-buffer buffer)
- (goto-char (point-max))
- (insert-buffer-substring (process-buffer process))
+ (set-buffer buffer)
+ (goto-char (point-max))
+ (insert-buffer-substring (process-buffer process))
;; Nix out "nntp reading...." message.
(when nntp-have-messaged
(setq nntp-have-messaged nil)
(save-excursion
(set-buffer nntp-server-buffer)
(erase-buffer)))
- (nntp-retrieve-data
- (mapconcat 'identity strings " ")
- nntp-address nntp-port-number nntp-server-buffer
- wait-for nnheader-callback-function))
+ (let* ((command (mapconcat 'identity strings " "))
+ (buffer (process-buffer (nntp-find-connection nntp-server-buffer)))
+ (pos (with-current-buffer buffer (point))))
+ (prog1
+ (nntp-retrieve-data command
+ nntp-address nntp-port-number nntp-server-buffer
+ wait-for nnheader-callback-function)
+ ;; If nothing to wait for, still remove possibly echo'ed commands
+ (unless wait-for
+ (nntp-accept-response)
+ (save-excursion
+ (set-buffer buffer)
+ (goto-char pos)
+ (if (looking-at (regexp-quote command))
+ (delete-region pos (progn (forward-line 1) (gnus-point-at-bol))))
+ )))
+ ))
(defun nntp-send-command-nodelete (wait-for &rest strings)
"Send STRINGS to server and wait until WAIT-FOR returns."
- (nntp-retrieve-data
- (mapconcat 'identity strings " ")
- nntp-address nntp-port-number nntp-server-buffer
- wait-for nnheader-callback-function))
+ (let* ((command (mapconcat 'identity strings " "))
+ (buffer (process-buffer (nntp-find-connection nntp-server-buffer)))
+ (pos (with-current-buffer buffer (point))))
+ (prog1
+ (nntp-retrieve-data command
+ nntp-address nntp-port-number nntp-server-buffer
+ wait-for nnheader-callback-function)
+ ;; If nothing to wait for, still remove possibly echo'ed commands
+ (unless wait-for
+ (nntp-accept-response)
+ (save-excursion
+ (set-buffer buffer)
+ (goto-char pos)
+ (if (looking-at (regexp-quote command))
+ (delete-region pos (progn (forward-line 1) (gnus-point-at-bol))))
+ )))
+ ))
(defun nntp-send-command-and-decode (wait-for &rest strings)
"Send STRINGS to server and wait until WAIT-FOR returns."
(save-excursion
(set-buffer nntp-server-buffer)
(erase-buffer)))
- (nntp-retrieve-data
- (mapconcat 'identity strings " ")
- nntp-address nntp-port-number nntp-server-buffer
- wait-for nnheader-callback-function t))
+ (let* ((command (mapconcat 'identity strings " "))
+ (buffer (process-buffer (nntp-find-connection nntp-server-buffer)))
+ (pos (with-current-buffer buffer (point))))
+ (prog1
+ (nntp-retrieve-data command
+ nntp-address nntp-port-number nntp-server-buffer
+ wait-for nnheader-callback-function t)
+ ;; If nothing to wait for, still remove possibly echo'ed commands
+ (unless wait-for
+ (nntp-accept-response)
+ (save-excursion
+ (set-buffer buffer)
+ (goto-char pos)
+ (if (looking-at (regexp-quote command))
+ (delete-region pos (progn (forward-line 1) (gnus-point-at-bol))))
+ )))
+ ))
+
(defun nntp-send-buffer (wait-for)
"Send the current buffer to server and wait until WAIT-FOR returns."
(not nntp-nov-is-evil)
(nntp-retrieve-headers-with-xover articles fetch-old))
;; We successfully retrieved the headers via XOVER.
- 'nov
+ 'nov
;; XOVER didn't work, so we do it the hard, slow and inefficient
;; way.
(let ((number (length articles))
(setq last-point (point))
(< received count)))
(nntp-accept-response))))
-
+
;; Wait for the reply from the final command.
(unless (gnus-buffer-live-p buf)
(nnheader-report 'nntp "Connection to %s is closed." server)
(not (re-search-backward "^\\.\r?\n"
(- (point) 4) t)))))
(nntp-accept-response)))
-
+
;; Now all replies are received. We remove CRs.
(unless (gnus-buffer-live-p buf)
(nnheader-report 'nntp "Connection to %s is closed." server)
(goto-char (point-min))
(while (search-forward "\r" nil t)
(replace-match "" t t))
-
+
(if (not nntp-server-list-active-group)
(progn
(copy-to-buffer nntp-server-buffer (point-min) (point-max))
(progn (forward-line 1) (point))))
(copy-to-buffer nntp-server-buffer (point-min) (point-max))
'active))))))
-
+
(deffoo nntp-retrieve-articles (articles &optional group server)
(nntp-possibly-change-group group server)
(save-excursion
(nntp-possibly-change-group nil server)
(save-excursion
(set-buffer nntp-server-buffer)
- (prog1
- (nntp-send-command
- "^\\.\r?\n" "NEWGROUPS"
- (format-time-string "%y%m%d %H%M%S" (date-to-time date)))
- (nntp-decode-text))))
+ (let* ((time (date-to-time date))
+ (ls (- (cadr time) (nth 8 (decode-time time)))))
+ (cond ((< ls 0)
+ (setcar time (1- (car time)))
+ (setcar (cdr time) (+ ls 65536)))
+ ((>= ls 65536)
+ (setcar time (1+ (car time)))
+ (setcar (cdr time) (- ls 65536)))
+ (t
+ (setcar (cdr time) ls)))
+ (prog1
+ (nntp-send-command
+ "^\\.\r?\n" "NEWGROUPS"
+ (format-time-string "%y%m%d %H%M%S" time)
+ "GMT")
+ (nntp-decode-text)))))
(deffoo nntp-request-post (&optional server)
(nntp-possibly-change-group nil server)
(when (nntp-send-command "^[23].*\r?\n" "POST")
- (nntp-send-buffer "^[23].*\n")))
+ (let ((response (with-current-buffer nntp-server-buffer
+ nntp-process-response))
+ server-id)
+ (when (and response
+ (string-match "^[23].*\\(<[^\t\n @<>]+@[^\t\n @<>]+>\\)"
+ response))
+ (setq server-id (match-string 1 response))
+ (narrow-to-region (goto-char (point-min))
+ (if (search-forward "\n\n" nil t)
+ (1- (point))
+ (point-max)))
+ (unless (mail-fetch-field "Message-ID")
+ (goto-char (point-min))
+ (insert "Message-ID: " server-id "\n"))
+ (widen))
+ (run-hooks 'nntp-prepare-post-hook)
+ (nntp-send-buffer "^[23].*\n"))))
(deffoo nntp-request-type (group article)
'news)
(process
(condition-case ()
(let ((coding-system-for-read nntp-coding-system-for-read)
- (coding-system-for-write nntp-coding-system-for-write))
+ (coding-system-for-write nntp-coding-system-for-write))
(funcall nntp-open-connection-function pbuffer))
(error nil)
(quit
(open-network-stream "nntpd" buffer nntp-address nntp-port-number))
(defun nntp-open-ssl-stream (buffer)
- (let* ((ssl-program-arguments '("-connect" (concat host ":" service)))
- (proc (open-ssl-stream "nntpd" buffer nntp-address nntp-port-number)))
+ (let ((proc (open-ssl-stream "nntpd" buffer nntp-address nntp-port-number)))
(save-excursion
(set-buffer buffer)
(nntp-wait-for-string "^\r*20[01]")
(goto-char (point-max))
(when (re-search-backward
nntp-process-wait-for nntp-process-start-point t)
+ (let ((response (match-string 0)))
+ (with-current-buffer nntp-server-buffer
+ (setq nntp-process-response response)))
(nntp-async-stop process)
;; convert it.
(when (gnus-buffer-exists-p nntp-process-to-buffer)
(while (and (cdr articles)
(< (- (nth 1 articles) (car articles)) nntp-nov-gap))
(setq articles (cdr articles)))
-
+
(setq in-process-buffer-p (stringp nntp-server-xover))
(nntp-send-xover-command first (car articles))
(setq articles (cdr articles))
-
+
(when (and nntp-server-xover in-process-buffer-p)
;; Don't count tried request.
(setq count (1+ count))
(setq nntp-server-xover nil)))
nntp-server-xover))))
-;;; Alternative connection methods.
+(defun nntp-find-group-and-number ()
+ (save-excursion
+ (save-restriction
+ (set-buffer nntp-server-buffer)
+ (narrow-to-region (goto-char (point-min))
+ (or (search-forward "\n\n" nil t) (point-max)))
+ (goto-char (point-min))
+ ;; We first find the number by looking at the status line.
+ (let ((number (and (looking-at "2[0-9][0-9] +\\([0-9]+\\) ")
+ (string-to-int
+ (buffer-substring (match-beginning 1)
+ (match-end 1)))))
+ group newsgroups xref)
+ (and number (zerop number) (setq number nil))
+ ;; Then we find the group name.
+ (setq group
+ (cond
+ ;; If there is only one group in the Newsgroups header,
+ ;; then it seems quite likely that this article comes
+ ;; from that group, I'd say.
+ ((and (setq newsgroups (mail-fetch-field "newsgroups"))
+ (not (string-match "," newsgroups)))
+ newsgroups)
+ ;; If there is more than one group in the Newsgroups
+ ;; header, then the Xref header should be filled out.
+ ;; We hazard a guess that the group that has this
+ ;; article number in the Xref header is the one we are
+ ;; looking for. This might very well be wrong if this
+ ;; article happens to have the same number in several
+ ;; groups, but that's life.
+ ((and (setq xref (mail-fetch-field "xref"))
+ number
+ (string-match (format "\\([^ :]+\\):%d" number) xref))
+ (substring xref (match-beginning 1) (match-end 1)))
+ (t "")))
+ (when (string-match "\r" group)
+ (setq group (substring group 0 (match-beginning 0))))
+ (cons group number)))))
(defun nntp-wait-for-string (regexp)
"Wait until string arrives in the buffer."
(set-buffer buf)
(goto-char (point-min)))))
+
+;; ==========================================================================
+;; Obsolete nntp-open-* connection methods -- drv
+;; ==========================================================================
+
+(defvoo nntp-open-telnet-envuser nil
+ "*If non-nil, telnet session (client and server both) will support the ENVIRON option and not prompt for login name.")
+
+(defvoo nntp-telnet-shell-prompt "bash\\|\$ *\r?$\\|> *\r?"
+ "*Regular expression to match the shell prompt on the remote machine.")
+
+(defvoo nntp-rlogin-program "rsh"
+ "*Program used to log in on remote machines.
+The default is \"rsh\", but \"ssh\" is a popular alternative.")
+
+(defvoo nntp-rlogin-parameters '("telnet" "-8" "${NNTPSERVER:=news}" "nntp")
+ "*Parameters to `nntp-open-rlogin'.
+That function may be used as `nntp-open-connection-function'. In that
+case, this list will be used as the parameter list given to rsh.")
+
+(defvoo nntp-rlogin-user-name nil
+ "*User name on remote system when using the rlogin connect method.")
+
+(defvoo nntp-telnet-parameters
+ '("exec" "telnet" "-8" "${NNTPSERVER:=news}" "nntp")
+ "*Parameters to `nntp-open-telnet'.
+That function may be used as `nntp-open-connection-function'. In that
+case, this list will be executed as a command after logging in
+via telnet.")
+
+(defvoo nntp-telnet-user-name nil
+ "User name to log in via telnet with.")
+
+(defvoo nntp-telnet-passwd nil
+ "Password to use to log in via telnet with.")
+
(defun nntp-open-telnet (buffer)
(save-excursion
(set-buffer buffer)
(delete-region (point-min) (point))
proc)))
-(defun nntp-find-group-and-number ()
+
+;; ==========================================================================
+;; Replacements for the nntp-open-* functions -- drv
+;; ==========================================================================
+
+(defun nntp-open-telnet-stream (buffer)
+ "Open a nntp connection by telnet'ing the news server.
+
+Please refer to the following variables to customize the connection:
+- `nntp-pre-command',
+- `nntp-telnet-command',
+- `nntp-telnet-switches',
+- `nntp-address',
+- `nntp-port-number',
+- `nntp-end-of-line'."
+ (let ((command `(,nntp-telnet-command
+ ,@nntp-telnet-switches
+ ,nntp-address ,nntp-port-number))
+ proc)
+ (and nntp-pre-command
+ (push nntp-pre-command command))
+ (setq proc (apply 'start-process "nntpd" buffer command))
+ (save-excursion
+ (set-buffer buffer)
+ (nntp-wait-for-string "^\r*20[01]")
+ (beginning-of-line)
+ (delete-region (point-min) (point))
+ proc)))
+
+(defun nntp-open-via-rlogin-and-telnet (buffer)
+ "Open a connection to an nntp server through an intermediate host.
+First rlogin to the remote host, and then telnet the real news server
+from there.
+
+Please refer to the following variables to customize the connection:
+- `nntp-pre-command',
+- `nntp-via-rlogin-command',
+- `nntp-via-user-name',
+- `nntp-via-address',
+- `nntp-telnet-command',
+- `nntp-telnet-switches',
+- `nntp-address',
+- `nntp-port-number',
+- `nntp-end-of-line'."
+ (let ((command `(,nntp-via-address
+ ,nntp-telnet-command
+ ,@nntp-telnet-switches
+ ,nntp-address ,nntp-port-number))
+ proc)
+ (and nntp-via-user-name
+ (setq command `("-l" ,nntp-via-user-name ,@command)))
+ (push nntp-via-rlogin-command command)
+ (and nntp-pre-command
+ (push nntp-pre-command command))
+ (setq proc (apply 'start-process "nntpd" buffer command))
+ (save-excursion
+ (set-buffer buffer)
+ (nntp-wait-for-string "^\r*20[01]")
+ (beginning-of-line)
+ (delete-region (point-min) (point))
+ proc)))
+
+(defun nntp-open-via-telnet-and-telnet (buffer)
+ "Open a connection to an nntp server through an intermediate host.
+First telnet the remote host, and then telnet the real news server
+from there.
+
+Please refer to the following variables to customize the connection:
+- `nntp-pre-command',
+- `nntp-via-telnet-command',
+- `nntp-via-telnet-switches',
+- `nntp-via-address',
+- `nntp-via-envuser',
+- `nntp-via-user-name',
+- `nntp-via-user-password',
+- `nntp-via-shell-prompt',
+- `nntp-telnet-command',
+- `nntp-telnet-switches',
+- `nntp-address',
+- `nntp-port-number',
+- `nntp-end-of-line'."
(save-excursion
- (save-restriction
- (set-buffer nntp-server-buffer)
- (narrow-to-region (goto-char (point-min))
- (or (search-forward "\n\n" nil t) (point-max)))
- (goto-char (point-min))
- ;; We first find the number by looking at the status line.
- (let ((number (and (looking-at "2[0-9][0-9] +\\([0-9]+\\) ")
- (string-to-int
- (buffer-substring (match-beginning 1)
- (match-end 1)))))
- group newsgroups xref)
- (and number (zerop number) (setq number nil))
- ;; Then we find the group name.
- (setq group
- (cond
- ;; If there is only one group in the Newsgroups header,
- ;; then it seems quite likely that this article comes
- ;; from that group, I'd say.
- ((and (setq newsgroups (mail-fetch-field "newsgroups"))
- (not (string-match "," newsgroups)))
- newsgroups)
- ;; If there is more than one group in the Newsgroups
- ;; header, then the Xref header should be filled out.
- ;; We hazard a guess that the group that has this
- ;; article number in the Xref header is the one we are
- ;; looking for. This might very well be wrong if this
- ;; article happens to have the same number in several
- ;; groups, but that's life.
- ((and (setq xref (mail-fetch-field "xref"))
- number
- (string-match (format "\\([^ :]+\\):%d" number) xref))
- (substring xref (match-beginning 1) (match-end 1)))
- (t "")))
- (when (string-match "\r" group)
- (setq group (substring group 0 (match-beginning 0))))
- (cons group number)))))
+ (set-buffer buffer)
+ (erase-buffer)
+ (let ((command `(,nntp-via-telnet-command ,@nntp-via-telnet-switches))
+ (case-fold-search t)
+ proc)
+ (and nntp-pre-command (push nntp-pre-command command))
+ (setq proc (apply 'start-process "nntpd" buffer command))
+ (when (memq (process-status proc) '(open run))
+ (nntp-wait-for-string "^r?telnet")
+ (process-send-string proc "set escape \^X\n")
+ (cond
+ ((and nntp-via-envuser nntp-via-user-name)
+ (process-send-string proc (concat "open " "-l" nntp-via-user-name
+ nntp-via-address "\n")))
+ (t
+ (process-send-string proc (concat "open " nntp-via-address
+ "\n"))))
+ (when (not nntp-via-envuser)
+ (nntp-wait-for-string "^\r*.?login:")
+ (process-send-string proc
+ (concat
+ (or nntp-via-user-name
+ (setq nntp-via-user-name
+ (read-string "login: ")))
+ "\n")))
+ (nntp-wait-for-string "^\r*.?password:")
+ (process-send-string proc
+ (concat
+ (or nntp-via-user-password
+ (setq nntp-via-user-password
+ (mail-source-read-passwd
+ "Password: ")))
+ "\n"))
+ (nntp-wait-for-string nntp-via-shell-prompt)
+ (let ((real-telnet-command `("exec"
+ ,nntp-telnet-command
+ ,@nntp-telnet-switches
+ ,nntp-address
+ ,nntp-port-number)))
+ (process-send-string proc
+ (concat (mapconcat 'identity
+ real-telnet-command " ")
+ "\n")))
+ (nntp-wait-for-string "^\r*20[01]")
+ (beginning-of-line)
+ (delete-region (point-min) (point))
+ (process-send-string proc "\^]")
+ (nntp-wait-for-string "^r?telnet")
+ (process-send-string proc "mode character\n")
+ (accept-process-output proc 1)
+ (sit-for 1)
+ (goto-char (point-min))
+ (forward-line 1)
+ (delete-region (point) (point-max)))
+ proc)))
(provide 'nntp)
-;;; nnultimate.el --- interfacing with the Ultimate Bulletin Board system -*- coding: iso-latin-1 -*-
-;; Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+;;; nnultimate.el --- interfacing with the Ultimate Bulletin Board system
+
+;; Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;; Keywords: news
(require 'gnus)
(require 'nnmail)
(require 'mm-util)
-(eval-when-compile
- (ignore-errors
- (require 'nnweb)))
-;; Report failure to find w3 at load time if appropriate.
-(eval '(require 'nnweb))
+(require 'mm-url)
+(require 'nnweb)
+(autoload 'w3-parse-buffer "w3-parse")
(nnoo-declare nnultimate)
(defvoo nnultimate-groups nil)
(defvoo nnultimate-headers nil)
(defvoo nnultimate-articles nil)
-(defvar nnultimate-table-regexp
+(defvar nnultimate-table-regexp
"postings.*editpost\\|forumdisplay\\|Forum[0-9]+/HTML\\|getbio")
;;; Interface functions
(setq subject (nth 2 (assq (car elem) topics)))
(setq href (nth 3 (assq (car elem) topics)))
(if (= current-page 1)
- (nnweb-insert href)
+ (mm-url-insert href)
(string-match "\\.html$" href)
- (nnweb-insert (concat (substring href 0 (match-beginning 0))
+ (mm-url-insert (concat (substring href 0 (match-beginning 0))
"-" (number-to-string current-page)
(match-string 0 href))))
(goto-char (point-min))
(setq date (substring (car datel) (match-end 0))
datel nil))
(pop datel))
- (setq date (delete "" (split-string
- date "[-, \n\t\r \81Â \81Â \81Â ]")))
- (if (or (member "AM" date)
- (member "PM" date))
- (setq date (format
- "%s %s %s %s"
- (nth 1 date)
- (if (and (>= (length (nth 0 date)) 3)
- (assoc (downcase
- (substring (nth 0 date) 0 3))
- parse-time-months))
- (substring (nth 0 date) 0 3)
- (car (rassq (string-to-number (nth 0 date))
- parse-time-months)))
- (nth 2 date) (nth 3 date)))
- (setq date (format "%s %s %s %s"
- (car (rassq (string-to-number (nth 1 date))
- parse-time-months))
- (nth 0 date) (nth 2 date) (nth 3 date))))
+ (when date
+ (setq date (delete "" (split-string
+ date "[-, \n\t\r    ]")))
+ (if (or (member "AM" date)
+ (member "PM" date))
+ (setq date (format
+ "%s %s %s %s"
+ (nth 1 date)
+ (if (and (>= (length (nth 0 date)) 3)
+ (assoc (downcase
+ (substring (nth 0 date) 0 3))
+ parse-time-months))
+ (substring (nth 0 date) 0 3)
+ (car (rassq (string-to-number (nth 0 date))
+ parse-time-months)))
+ (nth 2 date) (nth 3 date)))
+ (setq date (format "%s %s %s %s"
+ (car (rassq (string-to-number (nth 1 date))
+ parse-time-months))
+ (nth 0 date) (nth 2 date) (nth 3 date)))))
(push
(cons
article
(deffoo nnultimate-request-list (&optional server)
(nnultimate-possibly-change-server nil server)
(mm-with-unibyte-buffer
- (nnweb-insert
+ (mm-url-insert
(if (string-match "/$" nnultimate-address)
(concat nnultimate-address "Ultimate.cgi")
nnultimate-address))
(mm-with-unibyte-buffer
(while furls
(erase-buffer)
- (nnweb-insert (pop furls))
+ (mm-url-insert (pop furls))
(goto-char (point-min))
(setq parse (w3-parse-buffer (current-buffer)))
(setq contents
nnultimate-groups-alist)
(with-temp-file (expand-file-name "groups" nnultimate-directory)
(prin1 nnultimate-groups-alist (current-buffer))))
-
+
(defun nnultimate-init (server)
"Initialize buffers and such."
(unless (file-exists-p nnultimate-directory)
(nnoo-declare nnvirtual)
(defvoo nnvirtual-always-rescan t
- "*If non-nil, always scan groups for unread articles when entering a group.
+ "If non-nil, always scan groups for unread articles when entering a group.
If this variable is nil and you read articles in a component group
after the virtual group has been activated, the read articles from the
component group will show up when you enter the virtual group.")
(defvoo nnvirtual-component-regexp nil
- "*Regexp to match component groups.")
+ "Regexp to match component groups.")
(defvoo nnvirtual-component-groups nil
"Component group in this nnvirtual group.")
;;; Commentary:
;; Note: You need to have `url' (w3 0.46) or greater version
-;; installed for this backend to work.
+;; installed for some functions of this backend to work.
-;; Todo:
+;; Todo:
;; 1. To support more web archives.
;; 2. Generalize webmail to other MHonArc archive.
(require 'nnmail)
(require 'mm-util)
(require 'mail-source)
-(eval-when-compile
- (ignore-errors
- (require 'w3)
- (require 'url)
- (require 'w3-forms)
- (require 'nnweb)))
-;; Report failure to find w3 at load time if appropriate.
-(eval '(progn
- (require 'w3)
- (require 'url)
- (require 'w3-forms)
- (require 'nnweb)))
+(require 'mm-url)
(nnoo-declare nnwarchive)
(defvar nnwarchive-type-definition
'((egroups
(address . "www.egroups.com")
- (open-url
- "http://www.egroups.com/login.cgi?&login_email=%s&login_password=%s"
+ (open-url
+ "http://www.egroups.com/login.cgi?&login_email=%s&login_password=%s"
nnwarchive-login nnwarchive-passwd)
- (list-url
+ (list-url
"http://www.egroups.com/mygroups")
(list-dissect . nnwarchive-egroups-list)
(list-groups . nnwarchive-egroups-list-groups)
- (xover-url
+ (xover-url
"http://www.egroups.com/messages/%s/%d" group aux)
- (xover-last-url
+ (xover-last-url
"http://www.egroups.com/messages/%s/" group)
(xover-page-size . 13)
(xover-dissect . nnwarchive-egroups-xover)
- (article-url
+ (article-url
"http://www.egroups.com/message/%s/%d?source=1" group article)
(article-dissect . nnwarchive-egroups-article)
(authentication . t)
(mail-archive
(address . "www.mail-archive.com")
(open-url)
- (list-url
+ (list-url
"http://www.mail-archive.com/lists.html")
(list-dissect . nnwarchive-mail-archive-list)
(list-groups . nnwarchive-mail-archive-list-groups)
- (xover-url
+ (xover-url
"http://www.mail-archive.com/%s/mail%d.html" group aux)
- (xover-last-url
+ (xover-last-url
"http://www.mail-archive.com/%s/maillist.html" group)
(xover-page-size)
(xover-dissect . nnwarchive-mail-archive-xover)
- (article-url
+ (article-url
"http://www.mail-archive.com/%s/msg%05d.html" group article1)
(article-dissect . nnwarchive-mail-archive-article)
(xover-files . nnwarchive-mail-archive-xover-files)
(let ((defs (cdr (assq type nnwarchive-type-definition)))
def)
(dolist (def defs)
- (set (intern (concat "nnwarchive-" (symbol-name (car def))))
+ (set (intern (concat "nnwarchive-" (symbol-name (car def))))
(cdr def)))))
(defmacro nnwarchive-backlog (&rest form)
`(let ((gnus-keep-backlog nnwarchive-keep-backlog)
- (gnus-backlog-buffer
+ (gnus-backlog-buffer
(format " *nnwarchive backlog %s*" nnwarchive-address))
(gnus-backlog-articles nnwarchive-backlog-articles)
(gnus-backlog-hashtb nnwarchive-backlog-hashtb))
(nnwarchive-backlog
(gnus-backlog-enter-article group number buffer)))
-(defun nnwarchive-get-article (article &optional group server buffer)
+(defun nnwarchive-get-article (article &optional group server buffer)
(if (numberp article)
(if (nnwarchive-backlog
- (gnus-backlog-request-article group article
+ (gnus-backlog-request-article group article
(or buffer nntp-server-buffer)))
(cons group article)
(let (contents)
(setq nnwarchive-passwd
(or nnwarchive-passwd
(mail-source-read-passwd
- (format "Password for %s at %s: "
+ (format "Password for %s at %s: "
nnwarchive-login server)))))
(unless nnwarchive-groups
(nnwarchive-read-groups))
(nnwarchive-open-server server)))
(defun nnwarchive-read-groups ()
- (let ((file (expand-file-name (concat "groups-" nnwarchive-address)
+ (let ((file (expand-file-name (concat "groups-" nnwarchive-address)
nnwarchive-directory)))
(when (file-exists-p file)
(with-temp-buffer
(setq nnwarchive-groups (read (current-buffer)))))))
(defun nnwarchive-write-groups ()
- (with-temp-file (expand-file-name (concat "groups-" nnwarchive-address)
+ (with-temp-file (expand-file-name (concat "groups-" nnwarchive-address)
nnwarchive-directory)
(prin1 nnwarchive-groups (current-buffer))))
(defun nnwarchive-init (server)
"Initialize buffers and such."
(let ((type (intern server)) (defs nnwarchive-type-definition) def)
- (cond
+ (cond
((equal server "")
(setq type nnwarchive-default-type))
((assq type nnwarchive-type-definition) t)
(format " *nnwarchive %s %s*" nnwarchive-type server)))))
(nnwarchive-set-default nnwarchive-type))
-(defun nnwarchive-encode-www-form-urlencoded (pairs)
- "Return PAIRS encoded for forms."
- (mapconcat
- (function
- (lambda (data)
- (concat (w3-form-encode-xwfu (car data)) "="
- (w3-form-encode-xwfu (cdr data)))))
- pairs "&"))
-
-(defun nnwarchive-fetch-form (url pairs)
- (let ((url-request-data (nnwarchive-encode-www-form-urlencoded pairs))
- (url-request-method "POST")
- (url-request-extra-headers
- '(("Content-type" . "application/x-www-form-urlencoded"))))
- (nnweb-insert url))
- t)
-
(defun nnwarchive-eval (expr)
(cond
((consp expr)
(defun nnwarchive-url (xurl)
(mm-with-unibyte-current-buffer
- (let ((url-confirmation-func 'identity)
+ (let ((url-confirmation-func 'identity) ;; Some hacks.
(url-cookie-multiple-line nil))
- (cond
+ (cond
((eq (car xurl) 'post)
(pop xurl)
- (nnwarchive-fetch-form (car xurl) (nnwarchive-eval (cdr xurl))))
+ (mm-url-fetch-form (car xurl) (nnwarchive-eval (cdr xurl))))
(t
- (nnweb-insert (apply 'format (nnwarchive-eval xurl))))))))
-
+ (mm-url-insert (apply 'format (nnwarchive-eval xurl))))))))
+
(defun nnwarchive-generate-active ()
(save-excursion
(set-buffer nntp-server-buffer)
(save-excursion
(let (articles)
(set-buffer nnwarchive-buffer)
- (dolist (group groups)
+ (dolist (group groups)
(erase-buffer)
(nnwarchive-url nnwarchive-xover-last-url)
(goto-char (point-min))
(when (re-search-forward "of \\([0-9]+\\)[ \t\n\r]*</title>" nil t)
- (setq articles (string-to-number (match-string 1))))
+ (setq articles (string-to-number (match-string 1))))
(let ((elem (assoc group nnwarchive-groups)))
(if elem
(setcar (cdr elem) articles)
(let ((case-fold-search t)
group description elem articles)
(goto-char (point-min))
- (while
+ (while
(re-search-forward "href=\"/group/\\([^/\"\> ]+\\)" nil t)
(setq group (match-string 1)
description (match-string 2))
(push (cons
article
(make-full-mail-header
- article
- (nnweb-decode-entities-string subject)
- (nnweb-decode-entities-string from)
+ article
+ (mm-url-decode-entities-string subject)
+ (mm-url-decode-entities-string from)
date
(concat "<" group "%"
- (number-to-string article)
+ (number-to-string article)
"@egroup.com>")
""
0 0 "")) nnwarchive-headers))))
(goto-char (point-min))
(while (re-search-forward "<a[^>]+>\\([^<]+\\)</a>" nil t)
(replace-match "\\1"))
- (nnweb-decode-entities)
+ (mm-url-decode-entities)
(buffer-string))
(defun nnwarchive-egroups-xover-files (group articles)
(let ((elem (assoc group nnwarchive-headers-cache)))
(if elem
(setcdr elem nnwarchive-headers)
- (push (cons group nnwarchive-headers)
+ (push (cons group nnwarchive-headers)
nnwarchive-headers-cache)))))))
(defun nnwarchive-mail-archive-list ()
subject (match-string 2))
(forward-line 1)
(unless (assq article nnwarchive-headers)
- (if (looking-at "<UL><LI><EM>From</EM>:\\([^&]+\\)<\\([^&]+\\)>")
+ (if (looking-at "<UL><LI><EM>From</EM>: *\\([^<]*[^< ]\\) *<\\([^&]+\\)>")
(progn
(setq from (match-string 1)
date (identity (match-string 2))))
(push (cons
article
(make-full-mail-header
- article
- (nnweb-decode-entities-string subject)
- (nnweb-decode-entities-string from)
+ article
+ (mm-url-decode-entities-string subject)
+ (mm-url-decode-entities-string from)
date
(format "<%05d%%%s>\n" (1- article) group)
""
(insert from-r13)
(let ((message-caesar-translation-table
(or nnwarchive-caesar-translation-table
- (setq nnwarchive-caesar-translation-table
+ (setq nnwarchive-caesar-translation-table
(nnwarchive-make-caesar-translation-table)))))
(message-caesar-region (point-min) (point-max))
(buffer-string)))))
(defun nnwarchive-mail-archive-article (group article)
- (let (p refs url mime e
- from subject date id
+ (let (p refs url mime e
+ from subject date id
done
(case-fold-serch t))
(save-restriction
(when (search-forward "X-Head-End" nil t)
(beginning-of-line)
(narrow-to-region (point-min) (point))
- (nnweb-decode-entities)
+ (mm-url-decode-entities)
(goto-char (point-min))
(while (search-forward "<!--X-" nil t)
(replace-match ""))
(goto-char (point-min))
(while (search-forward " -->" nil t)
(replace-match ""))
- (setq from
+ (setq from
(or (mail-fetch-field "from")
- (nnwarchive-from-r13
+ (nnwarchive-from-r13
(mail-fetch-field "from-r13"))))
(setq date (mail-fetch-field "date"))
(setq id (mail-fetch-field "message-id"))
(search-forward "</ul>" nil t)
(end-of-line)
(narrow-to-region (point-min) (point))
- (nnweb-remove-markup)
- (nnweb-decode-entities)
+ (mm-url-remove-markup)
+ (mm-url-decode-entities)
(goto-char (point-min))
(delete-blank-lines)
(when from
(goto-char (point-max))
(widen)
(insert "\n"))
- (setq p (point))
+ (setq p (point))
(when (search-forward "X-Body-of-Message" nil t)
(forward-line)
(delete-region p (point))
(if (> (skip-chars-forward "\040\n\r\t") 0)
(delete-region (point-min) (point)))
(while (not (eobp))
- (cond
- ((looking-at "<PRE>\r?\n?")
+ (cond
+ ((looking-at "<PRE>\r?\n?")
(delete-region (match-beginning 0) (match-end 0))
(setq p (point))
(when (search-forward "</PRE>" nil t)
(delete-region (match-beginning 0) (match-end 0))
(save-restriction
(narrow-to-region p (point))
- (nnweb-remove-markup)
- (nnweb-decode-entities)
+ (mm-url-remove-markup)
+ (mm-url-decode-entities)
(goto-char (point-max)))))
((looking-at "<P><A HREF=\"\\([^\"]+\\)")
(setq url (match-string 1))
- (delete-region (match-beginning 0)
+ (delete-region (match-beginning 0)
(progn (forward-line) (point)))
- ;; I hate to download the url encode it, then immediately
+ ;; I hate to download the url encode it, then immediately
;; decode it.
(insert "<#external"
" type="
(mailcap-extension-to-mime
(match-string 0 url)))
"application/octet-stream")
- (format " url=\"http://www.mail-archive.com/%s/%s\""
+ (format " url=\"http://www.mail-archive.com/%s/%s\""
group url)
">\n"
"<#/external>")
(setq p (point))
(insert "<#part type=\"text/html\" disposition=inline>")
(goto-char
- (if (re-search-forward
- "[\040\n\r\t]*<PRE>\\|[\040\n\r\t]*<P><A HREF=\""
+ (if (re-search-forward
+ "[\040\n\r\t]*<PRE>\\|[\040\n\r\t]*<P><A HREF=\""
nil t)
(match-beginning 0)
(point-max)))
(insert " " (pop refs)))
(insert "\n"))
(when mime
- (unless (looking-at "$")
+ (unless (looking-at "$")
(search-forward "\n\n" nil t)
(forward-line -1))
(narrow-to-region (point) (point-max))
;;; Commentary:
-;; Note: You need to have `url' and `w3' installed for this
-;; backend to work.
+;; Note: You need to have `w3' installed for some functions to work.
;;; Code:
(require 'gnus)
(require 'nnmail)
(require 'mm-util)
-(eval-when-compile
- (ignore-errors
- (require 'w3)
- (require 'url)
- (require 'w3-forms)))
-
-;; Report failure to find w3 at load time if appropriate.
-(unless noninteractive
- (eval '(progn
- (require 'w3)
- (require 'url)
- (require 'w3-forms))))
+(require 'mm-url)
+(autoload 'w3-parse-buffer "w3-parse")
(nnoo-declare nnweb)
(defvoo nnweb-directory (nnheader-concat gnus-directory "nnweb/")
"Where nnweb will save its files.")
-(defvoo nnweb-type 'dejanews
+(defvoo nnweb-type 'google
"What search engine type is being used.
-Valid types include `dejanews', `dejanewsold', `reference',
+Valid types include `google', `dejanews', `dejanewsold', `reference',
and `altavista'.")
(defvar nnweb-type-definition
'(
- (dejanews ;; bought by google.com
- (article . nnweb-google-wash-article)
- (id . "http://groups.google.com/groups?as_umsgid=%s")
- (reference . nnweb-google-reference)
+ (google
+ ;;(article . nnweb-google-wash-article)
+ ;;(id . "http://groups.google.com/groups?as_umsgid=%s")
+ (article . ignore)
+ (id . "http://groups.google.com/groups?selm=%s&output=gplain")
+ ;;(reference . nnweb-google-reference)
+ (reference . identity)
+ (map . nnweb-google-create-mapping)
+ (search . nnweb-google-search)
+ (address . "http://groups.google.com/groups")
+ (identifier . nnweb-google-identity))
+ (dejanews ;; alias of google
+ ;;(article . nnweb-google-wash-article)
+ ;;(id . "http://groups.google.com/groups?as_umsgid=%s")
+ (article . ignore)
+ (id . "http://groups.google.com/groups?selm=%s&output=gplain")
+ ;;(reference . nnweb-google-reference)
+ (reference . identity)
(map . nnweb-google-create-mapping)
(search . nnweb-google-search)
(address . "http://groups.google.com/groups")
(deffoo nnweb-request-scan (&optional group server)
(nnweb-possibly-change-server group server)
+ (if nnweb-ephemeral-p
+ (setq nnweb-hashtb (gnus-make-hashtable 4095)))
(funcall (nnweb-definition 'map))
(unless nnweb-ephemeral-p
(nnweb-write-active)
(url (and header (mail-header-xref header))))
(when (or (and url
(mm-with-unibyte-current-buffer
- (nnweb-fetch-url url)))
+ (mm-url-insert url)))
(and (stringp article)
(nnweb-definition 'id t)
(let ((fetch (nnweb-definition 'id))
(when (string-match "^<\\(.*\\)>$" article)
(setq art (match-string 1 article)))
(when (and fetch art)
- (setq url (format fetch article))
+ (setq url (format fetch art))
(mm-with-unibyte-current-buffer
- (nnweb-fetch-url url))
+ (mm-url-insert url))
(if (nnweb-definition 'reference t)
(setq article
- (funcall (nnweb-definition
+ (funcall (nnweb-definition
'reference) article)))))))
(unless nnheader-callback-function
- (funcall (nnweb-definition 'article))
- (nnweb-decode-entities))
+ (funcall (nnweb-definition 'article)))
(nnheader-report 'nnweb "Fetched article %s" article)
(cons group (and (numberp article) article))))))
(nnweb-open-server server)))
(unless nnweb-group-alist
(nnweb-read-active))
+ (unless nnweb-hashtb
+ (setq nnweb-hashtb (gnus-make-hashtable 4095)))
(when group
(when (and (not nnweb-ephemeral-p)
- (not (equal group nnweb-group)))
- (setq nnweb-hashtb (gnus-make-hashtable 4095))
+ (equal group nnweb-group))
(nnweb-request-group group nil t))))
(defun nnweb-init (server)
nnweb-type nnweb-search server))
(current-buffer))))))
-(defun nnweb-fetch-url (url)
- (let (buf)
- (save-excursion
- (if (not nnheader-callback-function)
- (progn
- (with-temp-buffer
- (mm-enable-multibyte)
- (let ((coding-system-for-read 'binary)
- (coding-system-for-write 'binary)
- (default-process-coding-system 'binary))
- (nnweb-insert url))
- (setq buf (buffer-string)))
- (erase-buffer)
- (insert buf)
- t)
- (nnweb-url-retrieve-asynch
- url 'nnweb-callback (current-buffer) nnheader-callback-function)
- t))))
-
-(defun nnweb-callback (buffer callback)
- (when (gnus-buffer-live-p url-working-buffer)
- (save-excursion
- (set-buffer url-working-buffer)
- (funcall (nnweb-definition 'article))
- (nnweb-decode-entities)
- (set-buffer buffer)
- (goto-char (point-max))
- (insert-buffer-substring url-working-buffer))
- (funcall callback t)
- (gnus-kill-buffer url-working-buffer)))
-
-(defun nnweb-url-retrieve-asynch (url callback &rest data)
- (let ((url-request-method "GET")
- (old-asynch url-be-asynchronous)
- (url-request-data nil)
- (url-request-extra-headers nil)
- (url-working-buffer (generate-new-buffer-name " *nnweb*")))
- (setq-default url-be-asynchronous t)
- (save-excursion
- (set-buffer (get-buffer-create url-working-buffer))
- (setq url-current-callback-data data
- url-be-asynchronous t
- url-current-callback-func callback)
- (url-retrieve url nil))
- (setq-default url-be-asynchronous old-asynch)))
-
-(if (fboundp 'url-retrieve-synchronously)
- (defun nnweb-url-retrieve-asynch (url callback &rest data)
- (url-retrieve url callback data)))
+;; (defun nnweb-fetch-url (url)
+;; (let (buf)
+;; (save-excursion
+;; (if (not nnheader-callback-function)
+;; (progn
+;; (with-temp-buffer
+;; (mm-enable-multibyte)
+;; (let ((coding-system-for-read 'binary)
+;; (coding-system-for-write 'binary)
+;; (default-process-coding-system 'binary))
+;; (nnweb-insert url))
+;; (setq buf (buffer-string)))
+;; (erase-buffer)
+;; (insert buf)
+;; t)
+;; (nnweb-url-retrieve-asynch
+;; url 'nnweb-callback (current-buffer) nnheader-callback-function)
+;; t))))
+
+;; (defun nnweb-callback (buffer callback)
+;; (when (gnus-buffer-live-p url-working-buffer)
+;; (save-excursion
+;; (set-buffer url-working-buffer)
+;; (funcall (nnweb-definition 'article))
+;; (nnweb-decode-entities)
+;; (set-buffer buffer)
+;; (goto-char (point-max))
+;; (insert-buffer-substring url-working-buffer))
+;; (funcall callback t)
+;; (gnus-kill-buffer url-working-buffer)))
+
+;; (defun nnweb-url-retrieve-asynch (url callback &rest data)
+;; (let ((url-request-method "GET")
+;; (old-asynch url-be-asynchronous)
+;; (url-request-data nil)
+;; (url-request-extra-headers nil)
+;; (url-working-buffer (generate-new-buffer-name " *nnweb*")))
+;; (setq-default url-be-asynchronous t)
+;; (save-excursion
+;; (set-buffer (get-buffer-create url-working-buffer))
+;; (setq url-current-callback-data data
+;; url-be-asynchronous t
+;; url-current-callback-func callback)
+;; (url-retrieve url nil))
+;; (setq-default url-be-asynchronous old-asynch)))
+
+;; (if (fboundp 'url-retrieve-synchronously)
+;; (defun nnweb-url-retrieve-asynch (url callback &rest data)
+;; (url-retrieve url callback data)))
;;;
;;; DejaNews functions.
;; Yup -- fetch it.
(setq more (match-string 1))
(erase-buffer)
- (url-insert-file-contents more)))
+ (mm-url-insert more)))
;; Return the articles in the right order.
(setq nnweb-articles
(sort (nconc nnweb-articles map) 'car-less-than-car))))))
(defun nnweb-dejanews-search (search)
- (nnweb-insert
+ (mm-url-insert
(concat
(nnweb-definition 'address)
"?"
- (nnweb-encode-www-form-urlencoded
+ (mm-url-encode-www-form-urlencoded
`(("ST" . "PS")
("svcclass" . "dnyr")
("QRY" . ,search)
("ageweight" . "1")))))
t)
-(defun nnweb-dejanewsold-search (search)
- (nnweb-fetch-form
- (nnweb-definition 'address)
- `(("query" . ,search)
- ("defaultOp" . "AND")
- ("svcclass" . "dnold")
- ("maxhits" . "100")
- ("format" . "verbose2")
- ("threaded" . "0")
- ("showsort" . "date")
- ("agesign" . "1")
- ("ageweight" . "1")))
- t)
+;; (defun nnweb-dejanewsold-search (search)
+;; (nnweb-fetch-form
+;; (nnweb-definition 'address)
+;; `(("query" . ,search)
+;; ("defaultOp" . "AND")
+;; ("svcclass" . "dnold")
+;; ("maxhits" . "100")
+;; ("format" . "verbose2")
+;; ("threaded" . "0")
+;; ("showsort" . "date")
+;; ("agesign" . "1")
+;; ("ageweight" . "1")))
+;; t)
(defun nnweb-dejanews-identity (url)
"Return an unique identifier based on URL."
(goto-char (point-min))
(when (looking-at ".*href=\"\\([^\"]+\\)\"")
(setq url (match-string 1)))
- (nnweb-remove-markup)
+ (mm-url-remove-markup)
(goto-char (point-min))
(while (search-forward "\t" nil t)
(replace-match " "))
(let ((body (point-marker)))
(search-forward "</pre>" nil t)
(delete-region (point) (point-max))
- (nnweb-remove-markup)
+ (mm-url-remove-markup)
(goto-char (point-min))
(while (looking-at " *$")
(gnus-delete-line))
(while (search-forward "," nil t)
(replace-match " " t t)))
(widen)
+ (mm-url-decode-entities)
(set-marker body nil))))
(defun nnweb-reference-search (search)
- (url-insert-file-contents
+ (mm-url-insert
(concat
(nnweb-definition 'address)
"?"
- (nnweb-encode-www-form-urlencoded
+ (mm-url-encode-www-form-urlencoded
`(("search" . "advanced")
("querytext" . ,search)
("subj" . "")
(goto-char (point-min))
(while (search-forward "<dt>" nil t)
(replace-match "\n<blubb>"))
- (nnweb-decode-entities)
+ (mm-url-decode-entities)
(goto-char (point-min))
(while (re-search-forward "<blubb>.*href=\"\\([^\"]+\\)\"><strong>\\([^>]*\\)</strong></a><dd>\\([^-]+\\)- <b>\\([^<]+\\)<.*href=\"news:\\([^\"]+\\)\">.*\">\\(.+\\)</a><P>"
nil t)
(while (re-search-forward "<A.*\\?id@\\([^\"]+\\)\">[0-9]+</A>" nil t)
(replace-match "<\\1> " t)))
(widen)
- (nnweb-remove-markup)))
+ (mm-url-remove-markup)
+ (mm-url-decode-entities)))
(defun nnweb-altavista-search (search &optional part)
- (url-insert-file-contents
+ (mm-url-insert
(concat
(nnweb-definition 'address)
"?"
- (nnweb-encode-www-form-urlencoded
+ (mm-url-encode-www-form-urlencoded
`(("pg" . "aq")
("what" . "news")
,@(when part `(("stq" . ,(int-to-string (* part 30)))))
(goto-char (point-min))
(re-search-forward "^<pre>" nil t)
(narrow-to-region (point-min) (point))
- (search-backward "</table>" nil t 2)
+ (search-backward "<table " nil t 2)
(delete-region (point-min) (point))
- (if (search-forward "[view thread]" nil t)
+ (if (re-search-forward "Search Result [0-9]+" nil t)
+ (replace-match ""))
+ (if (re-search-forward "View complete thread ([0-9]+ articles?)" nil t)
(replace-match ""))
(goto-char (point-min))
(while (search-forward "<br>" nil t)
(replace-match "\n"))
- (nnweb-remove-markup)
+ (mm-url-remove-markup)
(goto-char (point-min))
(while (re-search-forward "^[ \t]*\n" nil t)
(replace-match ""))
(narrow-to-region (point) (point-max))
(search-forward "</pre>" nil t)
(delete-region (point) (point-max))
- (nnweb-remove-markup)
+ (mm-url-remove-markup)
(widen)))
(defun nnweb-google-parse-1 (&optional Message-ID)
(case-fold-search t)
(active (cadr (assoc nnweb-group nnweb-group-alist)))
Subject Score Date Newsgroups From
- map url)
+ map url mid)
(unless active
- (push (list nnweb-group (setq active (cons 1 0))
+ (push (list nnweb-group (setq active (cons 1 0))
nnweb-type nnweb-search)
nnweb-group-alist))
;; Go through all the article hits on this page.
(goto-char (point-min))
(while (re-search-forward
- "a href=/groups\\(\\?[^ \">]*seld=[0-9]+[^ \">]*\\)" nil t)
- (setq url
- (concat (nnweb-definition 'address)
- (match-string 1)))
+ "a href=/groups\\(\\?[^ \">]*selm=\\([^ &\">]+\\)\\)" nil t)
+ (setq mid (match-string 2)
+ url (format
+ "http://groups.google.com/groups?selm=%s&output=gplain" mid))
(narrow-to-region (search-forward ">" nil t)
(search-forward "</a>" nil t))
- (nnweb-remove-markup)
- (nnweb-decode-entities)
+ (mm-url-remove-markup)
+ (mm-url-decode-entities)
(setq Subject (buffer-string))
(goto-char (point-max))
(widen)
- (forward-line 2)
+ (forward-line 1)
(when (looking-at "<br><font[^>]+>")
(goto-char (match-end 0)))
(if (not (looking-at "<a[^>]+>"))
(skip-chars-forward " \t")
(narrow-to-region (point)
(search-forward "</a>" nil t))
- (nnweb-remove-markup)
- (nnweb-decode-entities)
+ (mm-url-remove-markup)
+ (mm-url-decode-entities)
(setq Newsgroups (buffer-string))
(goto-char (point-max))
(widen)
(skip-chars-forward "- \t"))
- (when (looking-at
- "\\([0-9]+/[A-Za-z]+/[0-9]+\\)[ \t]*by[ \t]*\\([^<]*\\) - <a")
+ (when (looking-at
+ "\\([0-9]+[/ ][A-Za-z]+[/ ][0-9]+\\)[ \t]*by[ \t]*\\([^<]*\\) - <a")
(setq From (match-string 2)
Date (match-string 1)))
(forward-line 1)
(incf (cdr active))
(make-full-mail-header
(cdr active) (if Newsgroups
- (concat "(" Newsgroups ") " Subject)
+ (concat "(" Newsgroups ") " Subject)
Subject)
- From Date Message-ID
+ From Date (or Message-ID mid)
nil 0 0 url))
map)
(nnweb-set-hashtb (cadar map) (car map))))
(defun nnweb-google-reference (id)
(let ((map (nnweb-google-parse-1 id)) header)
- (setq nnweb-articles
+ (setq nnweb-articles
(nconc nnweb-articles map))
(when (setq header (cadar map))
(mm-with-unibyte-current-buffer
- (nnweb-fetch-url (mail-header-xref header)))
+ (mm-url-insert (mail-header-xref header)))
(caar map))))
(defun nnweb-google-create-mapping ()
(sort nnweb-articles 'car-less-than-car))))))
(defun nnweb-google-search (search)
- (nnweb-insert
+ (mm-url-insert
(concat
(nnweb-definition 'address)
"?"
- (nnweb-encode-www-form-urlencoded
+ (mm-url-encode-www-form-urlencoded
`(("q" . ,search)
("num". "100")
("hq" . "")
(defun nnweb-google-identity (url)
"Return an unique identifier based on URL."
- (if (string-match "seld=\\([0-9]+\\)" url)
+ (if (string-match "selm=\\([^ &>]+\\)" url)
(match-string 1 url)
url))
(mapcar 'nnweb-insert-html (nth 2 parse))
(insert "</" (symbol-name (car parse)) ">\n")))
-(defun nnweb-encode-www-form-urlencoded (pairs)
- "Return PAIRS encoded for forms."
- (mapconcat
- (function
- (lambda (data)
- (concat (w3-form-encode-xwfu (car data)) "="
- (w3-form-encode-xwfu (cdr data)))))
- pairs "&"))
-
-(defun nnweb-fetch-form (url pairs)
- "Fetch a form from URL with PAIRS as the data using the POST method."
- (let ((url-request-data (nnweb-encode-www-form-urlencoded pairs))
- (url-request-method "POST")
- (url-request-extra-headers
- '(("Content-type" . "application/x-www-form-urlencoded"))))
- (url-insert-file-contents url)
- (setq buffer-file-name nil))
- t)
-
-(defun nnweb-decode-entities ()
- "Decode all HTML entities."
- (goto-char (point-min))
- (while (re-search-forward "&\\(#[0-9]+\\|[a-z]+\\);" nil t)
- (let ((elem (if (eq (aref (match-string 1) 0) ?\#)
- (let ((c
- (string-to-number (substring
- (match-string 1) 1))))
- (if (mm-char-or-char-int-p c) c 32))
- (or (cdr (assq (intern (match-string 1))
- w3-html-entities))
- ?#))))
- (unless (stringp elem)
- (setq elem (char-to-string elem)))
- (replace-match elem t t))))
-
-(defun nnweb-decode-entities-string (string)
- (with-temp-buffer
- (insert string)
- (nnweb-decode-entities)
- (buffer-substring (point-min) (point-max))))
-
-(defun nnweb-remove-markup ()
- "Remove all HTML markup, leaving just plain text."
- (goto-char (point-min))
- (while (search-forward "<!--" nil t)
- (delete-region (match-beginning 0)
- (or (search-forward "-->" nil t)
- (point-max))))
- (goto-char (point-min))
- (while (re-search-forward "<[^>]+>" nil t)
- (replace-match "" t t)))
-
-(defun nnweb-insert (url &optional follow-refresh)
- "Insert the contents from an URL in the current buffer.
-If FOLLOW-REFRESH is non-nil, redirect refresh url in META."
- (let ((name buffer-file-name))
- (if follow-refresh
- (save-restriction
- (narrow-to-region (point) (point))
- (url-insert-file-contents url)
- (goto-char (point-min))
- (when (re-search-forward
- "<meta[ \t\r\n]*http-equiv=\"Refresh\"[^>]*URL=\\([^\"]+\\)\"" nil t)
- (let ((url (match-string 1)))
- (delete-region (point-min) (point-max))
- (nnweb-insert url t))))
- (url-insert-file-contents url))
- (setq buffer-file-name name)))
-
(defun nnweb-parse-find (type parse &optional maxdepth)
"Find the element of TYPE in PARSE."
(catch 'found
(listp (cdr element)))
(nnweb-text-1 element)))))
-(defun nnweb-replace-in-string (string match newtext)
- (while (string-match match string)
- (setq string (replace-match newtext t t string)))
- string)
-
(provide 'nnweb)
;;; nnweb.el ends here
(require 'gnus)
(require 'nnmail)
(require 'mm-util)
-(eval-when-compile
- (ignore-errors
- (require 'nnweb)))
-;; Report failure to find w3 at load time if appropriate.
-(eval '(require 'nnweb))
+(require 'mm-url)
+(require 'nnweb)
+(autoload 'w3-parse-buffer "w3-parse")
(nnoo-declare nnwfm)
(defvoo nnwfm-groups nil)
(defvoo nnwfm-headers nil)
(defvoo nnwfm-articles nil)
-(defvar nnwfm-table-regexp
+(defvar nnwfm-table-regexp
"postings.*editpost\\|forumdisplay\\|Forum[0-9]+/HTML\\|getbio")
;;; Interface functions
(erase-buffer)
(setq subject (nth 2 (assq (car elem) topics))
thread-id (nth 0 (assq (car elem) topics)))
- (nnweb-insert
+ (mm-url-insert
(concat nnwfm-address
(format "Item.asp?GroupID=%d&ThreadID=%d" sid
thread-id)))
(deffoo nnwfm-request-list (&optional server)
(nnwfm-possibly-change-server nil server)
(mm-with-unibyte-buffer
- (nnweb-insert
+ (mm-url-insert
(if (string-match "/$" nnwfm-address)
(concat nnwfm-address "Group.asp")
nnwfm-address))
(setq description (car (last (nnweb-text (nth 1 row)))))
(setq articles
(string-to-number
- (nnweb-replace-in-string
+ (gnus-replace-in-string
(car (last (nnweb-text (nth 3 row)))) "," "")))
(when (and href
(string-match "GroupId=\\([0-9]+\\)" href))
(while furls
(erase-buffer)
(push (car furls) fetched-urls)
- (nnweb-insert (pop furls))
+ (mm-url-insert (pop furls))
(goto-char (point-min))
(while (re-search-forward " wr(" nil t)
(forward-char -1)
(setq elem (message-tokenize-header
- (nnweb-replace-in-string
+ (gnus-replace-in-string
(buffer-substring
(1+ (point))
(progn
"\\\\[\"\\\\]" "")))
(push (list
(string-to-number (nth 1 elem))
- (nnweb-replace-in-string (nth 2 elem) "\"" "")
+ (gnus-replace-in-string (nth 2 elem) "\"" "")
(string-to-number (nth 5 elem)))
forum-contents))
(when (re-search-forward "href=\"\\(Thread.*DateLast=\\([^\"]+\\)\\)"
nil t)
(setq url (match-string 1)
- time (nnwfm-date-to-time (url-unhex-string (match-string 2))))
+ time (nnwfm-date-to-time (gnus-url-unhex-string
+ (match-string 2))))
(when (and (nnwfm-new-threads-p group time)
(not (member
(setq url (concat
nnwfm-address
- (nnweb-decode-entities-string url)))
+ (mm-url-decode-entities-string url)))
fetched-urls)))
(push url furls))))
;; The main idea here is to map Gnus article numbers to
nnwfm-groups-alist)
(with-temp-file (expand-file-name "groups" nnwfm-directory)
(prin1 nnwfm-groups-alist (current-buffer))))
-
+
(defun nnwfm-init (server)
"Initialize buffers and such."
(unless (file-exists-p nnwfm-directory)
((equal 'pass pop3-authentication-scheme)
(pop3-user process pop3-maildrop)
(pop3-pass process))
- (t (error "Invalid POP3 authentication scheme.")))
+ (t (error "Invalid POP3 authentication scheme")))
(setq message-count (car (pop3-stat process)))
(pop3-quit process)
message-count))
(looking-at "\001\001\001\001\n") ; MMDF
(looking-at "BABYL OPTIONS:") ; Babyl
))
- (let ((from (mail-strip-quoted-names (mail-fetch-field "From")))
- (date (split-string (or (mail-fetch-field "Date")
- (pop3-make-date))
- " "))
- (From_))
+ (let* ((from (mail-strip-quoted-names (mail-fetch-field "From")))
+ (tdate (mail-fetch-field "Date"))
+ (date (split-string (or (and tdate
+ (not (string= "" tdate))
+ tdate)
+ (pop3-make-date))
+ " "))
+ (From_))
;; sample date formats I have seen
;; Date: Tue, 9 Jul 1996 09:04:21 -0400 (EDT)
;; Date: 08 Jul 1996 23:22:24 -0400
(pop3-send-command process (format "USER %s" user))
(let ((response (pop3-read-response process t)))
(if (not (and response (string-match "+OK" response)))
- (error (format "USER %s not valid." user)))))
+ (error (format "USER %s not valid" user)))))
(defun pop3-pass (process)
"Send authentication information to the server."
"Decode quoted-printable in the region between FROM and TO, per RFC 2045.
If CODING-SYSTEM is non-nil, decode bytes into characters with that
coding-system."
- (interactive "r")
+ (interactive
+ ;; Let the user determine the coding system with "C-x RET c".
+ (list (region-beginning) (region-end) coding-system-for-read))
(unless (mm-coding-system-p coding-system) ; e.g. `ascii' from Gnus
(setq coding-system nil))
(save-excursion
16)))
(insert byte)
(delete-char 3)
- ;; Why backward-char???
+ ;; Why backward-char???
;;(unless (eq byte 61) ;; 61 is not ?= in XEmacs
;; (backward-char))
))
rfc1843-hzp-word-regexp
rfc1843-word-regexp) (point-max) t)
;;; Text with extents may cause XEmacs crash
- (setq str (buffer-substring-no-properties
+ (setq str (buffer-substring-no-properties
(match-beginning 1)
(match-end 1)))
(setq firstc (aref str 0))
(ct (message-fetch-field "Content-Type" t))
(ctl (and ct (ignore-errors
(mail-header-parse-content-type ct)))))
- (if (and ctl (not (string-match "/" (car ctl))))
+ (if (and ctl (not (string-match "/" (car ctl))))
(setq ctl nil))
(goto-char (point-max))
(widen)
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
-
+
;; RFC 2045 is: "Multipurpose Internet Mail Extensions (MIME) Part
;; One: Format of Internet Message Bodies".
(point-max))))
(goto-char (point-min)))
+(defun rfc2047-field-value ()
+ "Return the value of the field at point."
+ (save-excursion
+ (save-restriction
+ (rfc2047-narrow-to-field)
+ (re-search-forward ":[ \t\n]*" nil t)
+ (buffer-substring (point) (point-max)))))
+
(defun rfc2047-encode-message-header ()
"Encode the message header according to `rfc2047-header-encoding-alist'.
Should be called narrowed to the head of the message."
(save-restriction
(rfc2047-narrow-to-field)
(if (not (rfc2047-encodable-p))
- (if (and (eq (mm-body-7-or-8) '8bit)
- (mm-multibyte-p)
- (mm-coding-system-p
- (car message-posting-charset)))
- ;; 8 bit must be decoded.
- ;; Is message-posting-charset a coding system?
- (mm-encode-coding-region
- (point-min) (point-max)
- (car message-posting-charset)))
+ (prog1
+ (if (and (eq (mm-body-7-or-8) '8bit)
+ (mm-multibyte-p)
+ (mm-coding-system-p
+ (car message-posting-charset)))
+ ;; 8 bit must be decoded.
+ ;; Is message-posting-charset a coding system?
+ (mm-encode-coding-region
+ (point-min) (point-max)
+ (car message-posting-charset))
+ nil)
+ ;; No encoding necessary, but folding is nice
+ (rfc2047-fold-region
+ (save-excursion
+ (goto-char (point-min))
+ (skip-chars-forward "^:")
+ (when (looking-at ": ")
+ (forward-char 2))
+ (point))
+ (point-max)))
;; We found something that may perhaps be encoded.
(setq method nil
alist rfc2047-header-encoding-alist)
mail-parse-charset)
(mm-encode-coding-region (point-min) (point-max)
mail-parse-charset)))
+ ;; We get this when CC'ing messsages to newsgroups with
+ ;; 8-bit names. The group name mail copy just get
+ ;; unconditionally encoded. Previously, it would ask
+ ;; whether to encode, which was quite confusing for the
+ ;; user. If the new behaviour is wrong, tell me. I have
+ ;; left the old code commented out below.
+ ;; -- Per Abrahamsen <abraham@dina.kvl.dk> Date: 2001-10-07.
((null method)
- (and (delq 'ascii
- (mm-find-charset-region (point-min)
- (point-max)))
- (if (or (message-options-get
- 'rfc2047-encode-message-header-encode-any)
- (message-options-set
- 'rfc2047-encode-message-header-encode-any
- (y-or-n-p
- "Some texts are not encoded. Encode anyway?")))
- (rfc2047-encode-region (point-min) (point-max))
- (error "Cannot send unencoded text."))))
+ (when (delq 'ascii
+ (mm-find-charset-region (point-min) (point-max)))
+ (rfc2047-encode-region (point-min) (point-max))))
+;;; ((null method)
+;;; (and (delq 'ascii
+;;; (mm-find-charset-region (point-min)
+;;; (point-max)))
+;;; (if (or (message-options-get
+;;; 'rfc2047-encode-message-header-encode-any)
+;;; (message-options-set
+;;; 'rfc2047-encode-message-header-encode-any
+;;; (y-or-n-p
+;;; "Some texts are not encoded. Encode anyway?")))
+;;; (rfc2047-encode-region (point-min) (point-max))
+;;; (error "Cannot send unencoded text"))))
((mm-coding-system-p method)
(if (and (featurep 'mule)
(if (boundp 'default-enable-multibyte-characters)
(insert "?=")
(forward-line 1)))))
+(defun rfc2047-fold-field ()
+ "Fold the current line."
+ (save-excursion
+ (save-restriction
+ (rfc2047-narrow-to-field)
+ (rfc2047-fold-region (point-min) (point-max)))))
+
(defun rfc2047-fold-region (b e)
"Fold long lines in region B to E."
(save-restriction
(goto-char (point-min))
(let ((break nil)
(qword-break nil)
+ (first t)
(bol (save-restriction
(widen)
(gnus-point-at-bol))))
(while (not (eobp))
- (when (and (or break qword-break) (> (- (point) bol) 76))
+ (when (and (or break qword-break)
+ (> (- (point) bol) 76))
(goto-char (or break qword-break))
(setq break nil
qword-break nil)
- (if (looking-at " \t")
+ (if (looking-at "[ \t]")
(insert "\n")
(insert "\n "))
(setq bol (1- (point)))
;; Don't break before the first non-LWSP characters.
(skip-chars-forward " \t")
- (unless (eobp) (forward-char 1)))
+ (unless (eobp)
+ (forward-char 1)))
(cond
((eq (char-after) ?\n)
(forward-char 1)
(forward-char 1))
((memq (char-after) '(? ?\t))
(skip-chars-forward " \t")
- (setq break (1- (point))))
+ (if first
+ ;; Don't break just after the header name.
+ (setq first nil)
+ (setq break (1- (point)))))
((not break)
(if (not (looking-at "=\\?[^=]"))
(if (eq (char-after) ?=)
(skip-chars-forward "^ \t\n\r")))
(t
(skip-chars-forward "^ \t\n\r"))))
- (when (and (or break qword-break) (> (- (point) bol) 76))
+ (when (and (or break qword-break)
+ (> (- (point) bol) 76))
(goto-char (or break qword-break))
(setq break nil
qword-break nil)
- (if (looking-at " \t")
+ (if (looking-at "[ \t]")
(insert "\n")
(insert "\n "))
(setq bol (1- (point)))
;; Don't break before the first non-LWSP characters.
(skip-chars-forward " \t")
- (unless (eobp) (forward-char 1))))))
+ (unless (eobp)
+ (forward-char 1))))))
+
+(defun rfc2047-unfold-field ()
+ "Fold the current line."
+ (save-excursion
+ (save-restriction
+ (rfc2047-narrow-to-field)
+ (rfc2047-unfold-region (point-min) (point-max)))))
(defun rfc2047-unfold-region (b e)
"Unfold lines in region B to E."
(while alist
(when (looking-at (caar alist))
(mm-with-unibyte-current-buffer-mule4
- (quoted-printable-encode-region
+ (quoted-printable-encode-region
(point-min) (point-max) nil (cdar alist)))
(subst-char-in-region (point-min) (point-max) ? ?_)
(setq alist nil))
;;; 1999-10-23 included in pgnus
;;; 2000-08-15 `rfc2104-hexstring-to-bitstring'
;;; 2000-05-12 added sha-1 example, added test case reference
-
+
+;;; Code:
+
(eval-when-compile (require 'cl))
;; Magic character for inner HMAC round. 0x36 == 54 == '6'
(defconst rfc2104-zero ?\x00)
;; Alist for converting hex to decimal.
-(defconst rfc2104-hex-alist
+(defconst rfc2104-hex-alist
'((?0 . 0) (?a . 10) (?A . 10)
(?1 . 1) (?b . 11) (?B . 11)
(?2 . 2) (?c . 12) (?C . 12)
(defun rfc2104-hash (hash block-length hash-length key text)
(let* (;; if key is longer than B, reset it to HASH(key)
- (key (if (> (length key) block-length)
+ (key (if (> (length key) block-length)
(funcall hash key) key))
(k_ipad (append key nil))
(k_opad (append key nil)))
;;; score-mode.el --- mode for editing Gnus score files
-;; Copyright (C) 1996 Free Software Foundation, Inc.
+
+;; Copyright (C) 1996, 2001 Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;; Keywords: news, mail
;;; Code:
(eval-when-compile (require 'cl))
-(require 'mm-util) ; for mm-auto-save-coding-system
+(require 'mm-util) ; for mm-universal-coding-system
(defvar gnus-score-mode-hook nil
"*Hook run in score mode buffers.")
"Syntax table used in score-mode buffers.")
;; We need this to cope with non-ASCII scoring.
-(defvar score-mode-coding-system mm-auto-save-coding-system)
+(defvar score-mode-coding-system mm-universal-coding-system)
;;;###autoload
(defun gnus-score-mode ()
--- /dev/null
+;;; sha1-el.el --- SHA1 Secure Hash Algorithm in Emacs-Lisp.
+
+;; Copyright (C) 1999, 2001 Free Software Foundation, Inc.
+
+;; Author: Shuhei KOBAYASHI <shuhei@aqua.ocn.ne.jp>
+;; Keywords: SHA1, FIPS 180-1
+
+;; This file is part of FLIM (Faithful Library about Internet Message).
+
+;; 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 2, 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; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; This program is implemented from the definition of SHA-1 in FIPS PUB
+;; 180-1 (Federal Information Processing Standards Publication 180-1),
+;; "Announcing the Standard for SECURE HASH STANDARD".
+;; <URL:http://www.itl.nist.gov/div897/pubs/fip180-1.htm>
+;; (EXCEPTION; two optimizations taken from GnuPG/cipher/sha1.c)
+;;
+;; Test cases from FIPS PUB 180-1.
+;;
+;; (sha1 "abc")
+;; => a9993e364706816aba3e25717850c26c9cd0d89d
+;;
+;; (sha1 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")
+;; => 84983e441c3bd26ebaae4aa1f95129e5e54670f1
+;;
+;; (sha1 (make-string 1000000 ?a))
+;; => 34aa973cd4c4daa4f61eeb2bdbad27316534016f
+;;
+;; BUGS:
+;; * It is assumed that length of input string is less than 2^29 bytes.
+;; * It is caller's responsibility to make string (or region) unibyte.
+;;
+;; TODO:
+;; * Rewrite from scratch!
+;; This version is much faster than Keiichi Suzuki's another sha1.el,
+;; but it is too dirty.
+
+;;; Code:
+
+(require 'hex-util)
+
+(autoload 'executable-find "executable")
+
+;;;
+;;; external SHA1 function.
+;;;
+
+(defvar sha1-maximum-internal-length 500
+ "*Maximum length of message to use lisp version of SHA1 function.
+If message is longer than this, `sha1-program' is used instead.
+
+If this variable is set to 0, use extarnal program only.
+If this variable is set to nil, use internal function only.")
+
+(defvar sha1-program '("openssl" "sha1")
+ "*Name of program to compute SHA1.
+It must be a string \(program name\) or list of strings \(name and its args\).")
+
+(defvar sha1-use-external
+ (executable-find (car sha1-program))
+ "*Use external sh1 program.
+If this variable is set to nil, use internal function only.")
+
+(defun sha1-string-external (string)
+ ;; `with-temp-buffer' is new in v20, so we do not use it.
+ (save-excursion
+ (let (buffer)
+ (unwind-protect
+ (let (prog args)
+ (if (consp sha1-program)
+ (setq prog (car sha1-program)
+ args (cdr sha1-program))
+ (setq prog sha1-program
+ args nil))
+ (setq buffer (set-buffer
+ (generate-new-buffer " *sha1 external*")))
+ (insert string)
+ (apply (function call-process-region)
+ (point-min)(point-max)
+ prog t t nil args)
+ ;; SHA1 is 40 bytes long in hexadecimal form.
+ (buffer-substring (point-min)(+ (point-min) 40)))
+ (and buffer
+ (buffer-name buffer)
+ (kill-buffer buffer))))))
+
+(defun sha1-region-external (beg end)
+ (sha1-string-external (buffer-substring-no-properties beg end)))
+
+;;;
+;;; internal SHA1 function.
+;;;
+
+(eval-when-compile
+ ;; optional second arg of string-to-number is new in v20.
+ (defconst sha1-K0-high 23170) ; (string-to-number "5A82" 16)
+ (defconst sha1-K0-low 31129) ; (string-to-number "7999" 16)
+ (defconst sha1-K1-high 28377) ; (string-to-number "6ED9" 16)
+ (defconst sha1-K1-low 60321) ; (string-to-number "EBA1" 16)
+ (defconst sha1-K2-high 36635) ; (string-to-number "8F1B" 16)
+ (defconst sha1-K2-low 48348) ; (string-to-number "BCDC" 16)
+ (defconst sha1-K3-high 51810) ; (string-to-number "CA62" 16)
+ (defconst sha1-K3-low 49622) ; (string-to-number "C1D6" 16)
+
+;;; original definition of sha1-F0.
+;;; (defmacro sha1-F0 (B C D)
+;;; (` (logior (logand (, B) (, C))
+;;; (logand (lognot (, B)) (, D)))))
+;;; a little optimization from GnuPG/cipher/sha1.c.
+ (defmacro sha1-F0 (B C D)
+ (` (logxor (, D) (logand (, B) (logxor (, C) (, D))))))
+ (defmacro sha1-F1 (B C D)
+ (` (logxor (, B) (, C) (, D))))
+;;; original definition of sha1-F2.
+;;; (defmacro sha1-F2 (B C D)
+;;; (` (logior (logand (, B) (, C))
+;;; (logand (, B) (, D))
+;;; (logand (, C) (, D)))))
+;;; a little optimization from GnuPG/cipher/sha1.c.
+ (defmacro sha1-F2 (B C D)
+ (` (logior (logand (, B) (, C))
+ (logand (, D) (logior (, B) (, C))))))
+ (defmacro sha1-F3 (B C D)
+ (` (logxor (, B) (, C) (, D))))
+
+ (defmacro sha1-S1 (W-high W-low)
+ (` (let ((W-high (, W-high))
+ (W-low (, W-low)))
+ (setq S1W-high (+ (% (* W-high 2) 65536)
+ (/ W-low (, (/ 65536 2)))))
+ (setq S1W-low (+ (/ W-high (, (/ 65536 2)))
+ (% (* W-low 2) 65536))))))
+ (defmacro sha1-S5 (A-high A-low)
+ (` (progn
+ (setq S5A-high (+ (% (* (, A-high) 32) 65536)
+ (/ (, A-low) (, (/ 65536 32)))))
+ (setq S5A-low (+ (/ (, A-high) (, (/ 65536 32)))
+ (% (* (, A-low) 32) 65536))))))
+ (defmacro sha1-S30 (B-high B-low)
+ (` (progn
+ (setq S30B-high (+ (/ (, B-high) 4)
+ (* (% (, B-low) 4) (, (/ 65536 4)))))
+ (setq S30B-low (+ (/ (, B-low) 4)
+ (* (% (, B-high) 4) (, (/ 65536 4))))))))
+
+ (defmacro sha1-OP (round)
+ (` (progn
+ (sha1-S5 sha1-A-high sha1-A-low)
+ (sha1-S30 sha1-B-high sha1-B-low)
+ (setq sha1-A-low (+ ((, (intern (format "sha1-F%d" round)))
+ sha1-B-low sha1-C-low sha1-D-low)
+ sha1-E-low
+ (, (symbol-value
+ (intern (format "sha1-K%d-low" round))))
+ (aref block-low idx)
+ (progn
+ (setq sha1-E-low sha1-D-low)
+ (setq sha1-D-low sha1-C-low)
+ (setq sha1-C-low S30B-low)
+ (setq sha1-B-low sha1-A-low)
+ S5A-low)))
+ (setq carry (/ sha1-A-low 65536))
+ (setq sha1-A-low (% sha1-A-low 65536))
+ (setq sha1-A-high (% (+ ((, (intern (format "sha1-F%d" round)))
+ sha1-B-high sha1-C-high sha1-D-high)
+ sha1-E-high
+ (, (symbol-value
+ (intern (format "sha1-K%d-high" round))))
+ (aref block-high idx)
+ (progn
+ (setq sha1-E-high sha1-D-high)
+ (setq sha1-D-high sha1-C-high)
+ (setq sha1-C-high S30B-high)
+ (setq sha1-B-high sha1-A-high)
+ S5A-high)
+ carry)
+ 65536)))))
+
+ (defmacro sha1-add-to-H (H X)
+ (` (progn
+ (setq (, (intern (format "sha1-%s-low" H)))
+ (+ (, (intern (format "sha1-%s-low" H)))
+ (, (intern (format "sha1-%s-low" X)))))
+ (setq carry (/ (, (intern (format "sha1-%s-low" H))) 65536))
+ (setq (, (intern (format "sha1-%s-low" H)))
+ (% (, (intern (format "sha1-%s-low" H))) 65536))
+ (setq (, (intern (format "sha1-%s-high" H)))
+ (% (+ (, (intern (format "sha1-%s-high" H)))
+ (, (intern (format "sha1-%s-high" X)))
+ carry)
+ 65536)))))
+ )
+
+;;; buffers (H0 H1 H2 H3 H4).
+(defvar sha1-H0-high)
+(defvar sha1-H0-low)
+(defvar sha1-H1-high)
+(defvar sha1-H1-low)
+(defvar sha1-H2-high)
+(defvar sha1-H2-low)
+(defvar sha1-H3-high)
+(defvar sha1-H3-low)
+(defvar sha1-H4-high)
+(defvar sha1-H4-low)
+
+(defun sha1-block (block-high block-low)
+ (let (;; step (c) --- initialize buffers (A B C D E).
+ (sha1-A-high sha1-H0-high) (sha1-A-low sha1-H0-low)
+ (sha1-B-high sha1-H1-high) (sha1-B-low sha1-H1-low)
+ (sha1-C-high sha1-H2-high) (sha1-C-low sha1-H2-low)
+ (sha1-D-high sha1-H3-high) (sha1-D-low sha1-H3-low)
+ (sha1-E-high sha1-H4-high) (sha1-E-low sha1-H4-low)
+ (idx 16))
+ ;; step (b).
+ (let (;; temporary variables used in sha1-S1 macro.
+ S1W-high S1W-low)
+ (while (< idx 80)
+ (sha1-S1 (logxor (aref block-high (- idx 3))
+ (aref block-high (- idx 8))
+ (aref block-high (- idx 14))
+ (aref block-high (- idx 16)))
+ (logxor (aref block-low (- idx 3))
+ (aref block-low (- idx 8))
+ (aref block-low (- idx 14))
+ (aref block-low (- idx 16))))
+ (aset block-high idx S1W-high)
+ (aset block-low idx S1W-low)
+ (setq idx (1+ idx))))
+ ;; step (d).
+ (setq idx 0)
+ (let (;; temporary variables used in sha1-OP macro.
+ S5A-high S5A-low S30B-high S30B-low carry)
+ (while (< idx 20) (sha1-OP 0) (setq idx (1+ idx)))
+ (while (< idx 40) (sha1-OP 1) (setq idx (1+ idx)))
+ (while (< idx 60) (sha1-OP 2) (setq idx (1+ idx)))
+ (while (< idx 80) (sha1-OP 3) (setq idx (1+ idx))))
+ ;; step (e).
+ (let (;; temporary variables used in sha1-add-to-H macro.
+ carry)
+ (sha1-add-to-H H0 A)
+ (sha1-add-to-H H1 B)
+ (sha1-add-to-H H2 C)
+ (sha1-add-to-H H3 D)
+ (sha1-add-to-H H4 E))))
+
+(defun sha1-binary (string)
+ "Return the SHA1 of STRING in binary form."
+ (let (;; prepare buffers for a block. byte-length of block is 64.
+ ;; input block is split into two vectors.
+ ;;
+ ;; input block: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ...
+ ;; block-high: +-0-+ +-1-+ +-2-+ +-3-+
+ ;; block-low: +-0-+ +-1-+ +-2-+ +-3-+
+ ;;
+ ;; length of each vector is 80, and elements of each vector are
+ ;; 16bit integers. elements 0x10-0x4F of each vector are
+ ;; assigned later in `sha1-block'.
+ (block-high (eval-when-compile (make-vector 80 nil)))
+ (block-low (eval-when-compile (make-vector 80 nil))))
+ (unwind-protect
+ (let* (;; byte-length of input string.
+ (len (length string))
+ (lim (* (/ len 64) 64))
+ (rem (% len 4))
+ (idx 0)(pos 0))
+ ;; initialize buffers (H0 H1 H2 H3 H4).
+ (setq sha1-H0-high 26437 ; (string-to-number "6745" 16)
+ sha1-H0-low 8961 ; (string-to-number "2301" 16)
+ sha1-H1-high 61389 ; (string-to-number "EFCD" 16)
+ sha1-H1-low 43913 ; (string-to-number "AB89" 16)
+ sha1-H2-high 39098 ; (string-to-number "98BA" 16)
+ sha1-H2-low 56574 ; (string-to-number "DCFE" 16)
+ sha1-H3-high 4146 ; (string-to-number "1032" 16)
+ sha1-H3-low 21622 ; (string-to-number "5476" 16)
+ sha1-H4-high 50130 ; (string-to-number "C3D2" 16)
+ sha1-H4-low 57840) ; (string-to-number "E1F0" 16)
+ ;; loop for each 64 bytes block.
+ (while (< pos lim)
+ ;; step (a).
+ (setq idx 0)
+ (while (< idx 16)
+ (aset block-high idx (+ (* (aref string pos) 256)
+ (aref string (1+ pos))))
+ (setq pos (+ pos 2))
+ (aset block-low idx (+ (* (aref string pos) 256)
+ (aref string (1+ pos))))
+ (setq pos (+ pos 2))
+ (setq idx (1+ idx)))
+ (sha1-block block-high block-low))
+ ;; last block.
+ (if (prog1
+ (< (- len lim) 56)
+ (setq lim (- len rem))
+ (setq idx 0)
+ (while (< pos lim)
+ (aset block-high idx (+ (* (aref string pos) 256)
+ (aref string (1+ pos))))
+ (setq pos (+ pos 2))
+ (aset block-low idx (+ (* (aref string pos) 256)
+ (aref string (1+ pos))))
+ (setq pos (+ pos 2))
+ (setq idx (1+ idx)))
+ ;; this is the last (at most) 32bit word.
+ (cond
+ ((= rem 3)
+ (aset block-high idx (+ (* (aref string pos) 256)
+ (aref string (1+ pos))))
+ (setq pos (+ pos 2))
+ (aset block-low idx (+ (* (aref string pos) 256)
+ 128)))
+ ((= rem 2)
+ (aset block-high idx (+ (* (aref string pos) 256)
+ (aref string (1+ pos))))
+ (aset block-low idx 32768))
+ ((= rem 1)
+ (aset block-high idx (+ (* (aref string pos) 256)
+ 128))
+ (aset block-low idx 0))
+ (t ;; (= rem 0)
+ (aset block-high idx 32768)
+ (aset block-low idx 0)))
+ (setq idx (1+ idx))
+ (while (< idx 16)
+ (aset block-high idx 0)
+ (aset block-low idx 0)
+ (setq idx (1+ idx))))
+ ;; last block has enough room to write the length of string.
+ (progn
+ ;; write bit length of string to last 4 bytes of the block.
+ (aset block-low 15 (* (% len 8192) 8))
+ (setq len (/ len 8192))
+ (aset block-high 15 (% len 65536))
+ ;; XXX: It is not practical to compute SHA1 of
+ ;; such a huge message on emacs.
+ ;; (setq len (/ len 65536)) ; for 64bit emacs.
+ ;; (aset block-low 14 (% len 65536))
+ ;; (aset block-high 14 (/ len 65536))
+ (sha1-block block-high block-low))
+ ;; need one more block.
+ (sha1-block block-high block-low)
+ (fillarray block-high 0)
+ (fillarray block-low 0)
+ ;; write bit length of string to last 4 bytes of the block.
+ (aset block-low 15 (* (% len 8192) 8))
+ (setq len (/ len 8192))
+ (aset block-high 15 (% len 65536))
+ ;; XXX: It is not practical to compute SHA1 of
+ ;; such a huge message on emacs.
+ ;; (setq len (/ len 65536)) ; for 64bit emacs.
+ ;; (aset block-low 14 (% len 65536))
+ ;; (aset block-high 14 (/ len 65536))
+ (sha1-block block-high block-low))
+ ;; make output string (in binary form).
+ (let ((result (make-string 20 0)))
+ (aset result 0 (/ sha1-H0-high 256))
+ (aset result 1 (% sha1-H0-high 256))
+ (aset result 2 (/ sha1-H0-low 256))
+ (aset result 3 (% sha1-H0-low 256))
+ (aset result 4 (/ sha1-H1-high 256))
+ (aset result 5 (% sha1-H1-high 256))
+ (aset result 6 (/ sha1-H1-low 256))
+ (aset result 7 (% sha1-H1-low 256))
+ (aset result 8 (/ sha1-H2-high 256))
+ (aset result 9 (% sha1-H2-high 256))
+ (aset result 10 (/ sha1-H2-low 256))
+ (aset result 11 (% sha1-H2-low 256))
+ (aset result 12 (/ sha1-H3-high 256))
+ (aset result 13 (% sha1-H3-high 256))
+ (aset result 14 (/ sha1-H3-low 256))
+ (aset result 15 (% sha1-H3-low 256))
+ (aset result 16 (/ sha1-H4-high 256))
+ (aset result 17 (% sha1-H4-high 256))
+ (aset result 18 (/ sha1-H4-low 256))
+ (aset result 19 (% sha1-H4-low 256))
+ result))
+ ;; do not leave a copy of input string.
+ (fillarray block-high nil)
+ (fillarray block-low nil))))
+
+(defun sha1-string-internal (string)
+ (encode-hex-string (sha1-binary string)))
+
+(defun sha1-region-internal (beg end)
+ (sha1-string-internal (buffer-substring-no-properties beg end)))
+
+;;;
+;;; application interface.
+;;;
+
+(defun sha1-region (beg end)
+ (if (and sha1-use-external
+ sha1-maximum-internal-length
+ (> (abs (- end beg)) sha1-maximum-internal-length))
+ (sha1-region-external beg end)
+ (sha1-region-internal beg end)))
+
+(defun sha1-string (string)
+ (if (and sha1-use-external
+ sha1-maximum-internal-length
+ (> (length string) sha1-maximum-internal-length))
+ (sha1-string-external string)
+ (sha1-string-internal string)))
+
+(defun sha1 (object &optional beg end)
+ "Return the SHA1 (Secure Hash Algorithm) of an object.
+OBJECT is either a string or a buffer.
+Optional arguments BEG and END denote buffer positions for computing the
+hash of a portion of OBJECT."
+ (if (stringp object)
+ (sha1-string object)
+ (save-excursion
+ (set-buffer object)
+ (sha1-region (or beg (point-min)) (or end (point-max))))))
+
+(provide 'sha1-el)
+
+;;; sha1-el.el ends here
--- /dev/null
+;;; sieve-manage.el --- Implementation of the managesive protocol in elisp
+;; Copyright (C) 2001 Free Software Foundation, Inc.
+
+;; Author: Simon Josefsson <simon@josefsson.org>
+
+;; This file is not part of GNU Emacs, but the same permissions apply.
+
+;; GNU Emacs 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 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; This library provides an elisp API for the managesieve network
+;; protocol.
+;;
+;; Currently only the CRAM-MD5 authentication mechanism is supported.
+;;
+;; The API should be fairly obvious for anyone familiar with the
+;; managesieve protocol, interface functions include:
+;;
+;; `sieve-manage-open'
+;; open connection to managesieve server, returning a buffer to be
+;; used by all other API functions.
+;;
+;; `sieve-manage-opened'
+;; check if a server is open or not
+;;
+;; `sieve-manage-close'
+;; close a server connection.
+;;
+;; `sieve-manage-authenticate'
+;; `sieve-manage-listscripts'
+;; performs managesieve protocol actions
+;;
+;; and that's it. Example of a managesieve session in *scratch*:
+;;
+;; (setq my-buf (sieve-manage-open "my.server.com"))
+;; " *sieve* my.server.com:2000*"
+;;
+;; (sieve-manage-authenticate "myusername" "mypassword" my-buf)
+;; 'auth
+;;
+;; (sieve-manage-listscripts my-buf)
+;; ("vacation" "testscript" ("splitmail") "badscript")
+;;
+;; References:
+;;
+;; draft-martin-managesieve-02.txt,
+;; "A Protocol for Remotely Managing Sieve Scripts",
+;; by Tim Martin.
+;;
+;; Release history:
+;;
+;; 2001-10-31 Committed to Oort Gnus.
+;;
+;; $Id: sieve-manage.el,v 1.1.1.1 2002-01-06 22:11:34 yamaoka Exp $
+
+;;; Code:
+
+(require 'rfc2104)
+(or (fboundp 'md5)
+ (require 'md5))
+(eval-and-compile
+ (autoload 'starttls-open-stream "starttls"))
+
+;; User customizable variables:
+
+(defgroup sieve-manage nil
+ "Low-level Managesieve protocol issues."
+ :group 'mail
+ :prefix "sieve-")
+
+(defcustom sieve-manage-log "*sieve-manage-log*"
+ "Name of buffer for managesieve session trace."
+ :type 'string)
+
+(defcustom sieve-manage-default-user (user-login-name)
+ "Default username to use."
+ :type 'string)
+
+(defcustom sieve-manage-server-eol "\r\n"
+ "The EOL string sent from the server."
+ :type 'string)
+
+(defcustom sieve-manage-client-eol "\r\n"
+ "The EOL string we send to the server."
+ :type 'string)
+
+(defcustom sieve-manage-streams '(network starttls shell)
+ "Priority of streams to consider when opening connection to server.")
+
+(defcustom sieve-manage-stream-alist
+ '((network sieve-manage-network-p sieve-manage-network-open)
+ (shell sieve-manage-shell-p sieve-manage-shell-open)
+ (starttls sieve-manage-starttls-p sieve-manage-starttls-open))
+ "Definition of network streams.
+
+\(NAME CHECK OPEN)
+
+NAME names the stream, CHECK is a function returning non-nil if the
+server support the stream and OPEN is a function for opening the
+stream.")
+
+(defcustom sieve-manage-authenticators '(cram-md5 plain)
+ "Priority of authenticators to consider when authenticating to server.")
+
+(defcustom sieve-manage-authenticator-alist
+ '((cram-md5 sieve-manage-cram-md5-p sieve-manage-cram-md5-auth)
+ (plain sieve-manage-plain-p sieve-manage-plain-auth))
+ "Definition of authenticators.
+
+\(NAME CHECK AUTHENTICATE)
+
+NAME names the authenticator. CHECK is a function returning non-nil if
+the server support the authenticator and AUTHENTICATE is a function
+for doing the actual authentication.")
+
+(defcustom sieve-manage-default-port 2000
+ "Default port number for managesieve protocol."
+ :type 'integer)
+
+;; Internal variables:
+
+(defconst sieve-manage-local-variables '(sieve-manage-server
+ sieve-manage-port
+ sieve-manage-auth
+ sieve-manage-stream
+ sieve-manage-username
+ sieve-manage-password
+ sieve-manage-process
+ sieve-manage-client-eol
+ sieve-manage-server-eol
+ sieve-manage-capability))
+(defconst sieve-manage-default-stream 'network)
+(defconst sieve-manage-coding-system-for-read 'binary)
+(defconst sieve-manage-coding-system-for-write 'binary)
+(defvar sieve-manage-stream nil)
+(defvar sieve-manage-auth nil)
+(defvar sieve-manage-server nil)
+(defvar sieve-manage-port nil)
+(defvar sieve-manage-username nil)
+(defvar sieve-manage-password nil)
+(defvar sieve-manage-state 'closed
+ "Managesieve state.
+Valid states are `closed', `initial', `nonauth', and `auth'.")
+(defvar sieve-manage-process nil)
+(defvar sieve-manage-capability nil)
+
+;; Internal utility functions
+
+(defsubst sieve-manage-disable-multibyte ()
+ "Enable multibyte in the current buffer."
+ (when (fboundp 'set-buffer-multibyte)
+ (set-buffer-multibyte nil)))
+
+(defun sieve-manage-read-passwd (prompt &rest args)
+ "Read a password using PROMPT.
+If ARGS, PROMPT is used as an argument to `format'."
+ (let ((prompt (if args
+ (apply 'format prompt args)
+ prompt)))
+ (funcall (if (or (fboundp 'read-passwd)
+ (and (load "subr" t)
+ (fboundp 'read-passwd))
+ (and (load "passwd" t)
+ (fboundp 'read-passwd)))
+ 'read-passwd
+ (autoload 'ange-ftp-read-passwd "ange-ftp")
+ 'ange-ftp-read-passwd)
+ prompt)))
+
+
+;; Uses the dynamically bound `reason' variable.
+(defvar reason)
+(defun sieve-manage-interactive-login (buffer loginfunc)
+ "Login to server in BUFFER.
+LOGINFUNC is passed a username and a password, it should return t if
+it where sucessful authenticating itself to the server, nil otherwise.
+Returns t if login was successful, nil otherwise."
+ (with-current-buffer buffer
+ (make-variable-buffer-local 'sieve-manage-username)
+ (make-variable-buffer-local 'sieve-manage-password)
+ (let (user passwd ret reason)
+ ;; (condition-case ()
+ (while (or (not user) (not passwd))
+ (setq user (or sieve-manage-username
+ (read-from-minibuffer
+ (concat "Managesieve username for "
+ sieve-manage-server ": ")
+ (or user sieve-manage-default-user))))
+ (setq passwd (or sieve-manage-password
+ (sieve-manage-read-passwd
+ (concat "Managesieve password for " user "@"
+ sieve-manage-server ": "))))
+ (when (and user passwd)
+ (if (funcall loginfunc user passwd)
+ (progn
+ (setq ret t
+ sieve-manage-username user)
+ (if (and (not sieve-manage-password)
+ (y-or-n-p "Store password for this session? "))
+ (setq sieve-manage-password passwd)))
+ (if reason
+ (message "Login failed (reason given: %s)..." reason)
+ (message "Login failed..."))
+ (setq reason nil)
+ (setq passwd nil)
+ (sit-for 1))))
+ ;; (quit (with-current-buffer buffer
+ ;; (setq user nil
+ ;; passwd nil)))
+ ;; (error (with-current-buffer buffer
+ ;; (setq user nil
+ ;; passwd nil))))
+ ret)))
+
+(defun sieve-manage-erase (&optional p buffer)
+ (let ((buffer (or buffer (current-buffer))))
+ (and sieve-manage-log
+ (with-current-buffer (get-buffer-create sieve-manage-log)
+ (sieve-manage-disable-multibyte)
+ (buffer-disable-undo)
+ (goto-char (point-max))
+ (insert-buffer-substring buffer (with-current-buffer buffer
+ (point-min))
+ (or p (with-current-buffer buffer
+ (point-max)))))))
+ (delete-region (point-min) (or p (point-max))))
+
+(defun sieve-manage-open-1 (buffer)
+ (with-current-buffer buffer
+ (sieve-manage-erase)
+ (setq sieve-manage-state 'initial
+ sieve-manage-process
+ (condition-case ()
+ (funcall (nth 2 (assq sieve-manage-stream
+ sieve-manage-stream-alist))
+ "sieve" buffer sieve-manage-server sieve-manage-port)
+ ((error quit) nil)))
+ (when sieve-manage-process
+ (while (and (eq sieve-manage-state 'initial)
+ (memq (process-status sieve-manage-process) '(open run)))
+ (message "Waiting for response from %s..." sieve-manage-server)
+ (accept-process-output sieve-manage-process 1))
+ (message "Waiting for response from %s...done" sieve-manage-server)
+ (and (memq (process-status sieve-manage-process) '(open run))
+ sieve-manage-process))))
+
+;; Streams
+
+(defun sieve-manage-network-p (buffer)
+ t)
+
+(defun sieve-manage-network-open (name buffer server port)
+ (let* ((port (or port sieve-manage-default-port))
+ (coding-system-for-read sieve-manage-coding-system-for-read)
+ (coding-system-for-write sieve-manage-coding-system-for-write)
+ (process (open-network-stream name buffer server port)))
+ (when process
+ (while (and (memq (process-status process) '(open run))
+ (set-buffer buffer) ;; XXX "blue moon" nntp.el bug
+ (goto-char (point-min))
+ (not (sieve-manage-parse-greeting-1)))
+ (accept-process-output process 1)
+ (sit-for 1))
+ (sieve-manage-erase nil buffer)
+ (when (memq (process-status process) '(open run))
+ process))))
+
+(defun imap-starttls-p (buffer)
+ ;; (and (imap-capability 'STARTTLS buffer)
+ (condition-case ()
+ (progn
+ (require 'starttls)
+ (call-process "starttls"))
+ (error nil)))
+
+(defun imap-starttls-open (name buffer server port)
+ (let* ((port (or port sieve-manage-default-port))
+ (coding-system-for-read sieve-manage-coding-system-for-read)
+ (coding-system-for-write sieve-manage-coding-system-for-write)
+ (process (starttls-open-stream name buffer server port))
+ done)
+ (when process
+ (while (and (memq (process-status process) '(open run))
+ (set-buffer buffer) ;; XXX "blue moon" nntp.el bug
+ (goto-char (point-min))
+ (not (sieve-manage-parse-greeting-1)))
+ (accept-process-output process 1)
+ (sit-for 1))
+ (sieve-manage-erase nil buffer)
+ (sieve-manage-send "STARTTLS")
+ (starttls-negotiate process))
+ (when (memq (process-status process) '(open run))
+ process)))
+
+;; Authenticators
+
+(defun sieve-manage-plain-p (buffer)
+ (sieve-manage-capability "SASL" "PLAIN" buffer))
+
+(defun sieve-manage-plain-auth (buffer)
+ "Login to managesieve server using the PLAIN SASL method."
+ (let* ((done (sieve-manage-interactive-login
+ buffer
+ (lambda (user passwd)
+ (sieve-manage-send (concat "AUTHENTICATE \"PLAIN\" \""
+ (base64-encode-string
+ (concat (char-to-string 0)
+ user
+ (char-to-string 0)
+ passwd))
+ "\""))
+ (let ((rsp (sieve-manage-parse-okno)))
+ (if (sieve-manage-ok-p rsp)
+ t
+ (setq reason (cdr-safe rsp))
+ nil))))))
+ (if done
+ (message "sieve: Authenticating using PLAIN...done")
+ (message "sieve: Authenticating using PLAIN...failed"))))
+
+(defun sieve-manage-cram-md5-p (buffer)
+ (sieve-manage-capability "SASL" "CRAM-MD5" buffer))
+
+(defun sieve-manage-cram-md5-auth (buffer)
+ "Login to managesieve server using the CRAM-MD5 SASL method."
+ (message "sieve: Authenticating using CRAM-MD5...")
+ (let* ((done (sieve-manage-interactive-login
+ buffer
+ (lambda (user passwd)
+ (sieve-manage-send "AUTHENTICATE \"CRAM-MD5\" \"\"")
+ (sieve-manage-send
+ (concat
+ "\""
+ (base64-encode-string
+ (concat
+ user " "
+ (rfc2104-hash 'md5 64 16 passwd
+ (base64-decode-string
+ (prog1
+ (sieve-manage-parse-string)
+ (sieve-manage-erase))))))
+ "\""))
+ (let ((rsp (sieve-manage-parse-okno)))
+ (if (sieve-manage-ok-p rsp)
+ t
+ (setq reason (cdr-safe rsp))
+ nil))))))
+ (if done
+ (message "sieve: Authenticating using CRAM-MD5...done")
+ (message "sieve: Authenticating using CRAM-MD5...failed"))))
+
+;; Managesieve API
+
+(defun sieve-manage-open (server &optional port stream auth buffer)
+ "Open a network connection to a managesieve SERVER (string).
+Optional variable PORT is port number (integer) on remote server.
+Optional variable STREAM is any of `sieve-manage-streams' (a symbol).
+Optional variable AUTH indicates authenticator to use, see
+`sieve-manage-authenticators' for available authenticators. If nil, chooses
+the best stream the server is capable of.
+Optional variable BUFFER is buffer (buffer, or string naming buffer)
+to work in."
+ (setq buffer (or buffer (format " *sieve* %s:%d" server (or port 2000))))
+ (with-current-buffer (get-buffer-create buffer)
+ (mapcar 'make-variable-buffer-local sieve-manage-local-variables)
+ (sieve-manage-disable-multibyte)
+ (buffer-disable-undo)
+ (setq sieve-manage-server (or server sieve-manage-server))
+ (setq sieve-manage-port (or port sieve-manage-port))
+ (setq sieve-manage-stream (or stream sieve-manage-stream))
+ (message "sieve: Connecting to %s..." sieve-manage-server)
+ (if (let ((sieve-manage-stream
+ (or sieve-manage-stream sieve-manage-default-stream)))
+ (sieve-manage-open-1 buffer))
+ ;; Choose stream.
+ (let (stream-changed)
+ (message "sieve: Connecting to %s...done" sieve-manage-server)
+ (when (null sieve-manage-stream)
+ (let ((streams sieve-manage-streams))
+ (while (setq stream (pop streams))
+ (if (funcall (nth 1 (assq stream
+ sieve-manage-stream-alist)) buffer)
+ (setq stream-changed
+ (not (eq (or sieve-manage-stream
+ sieve-manage-default-stream)
+ stream))
+ sieve-manage-stream stream
+ streams nil)))
+ (unless sieve-manage-stream
+ (error "Couldn't figure out a stream for server"))))
+ (when stream-changed
+ (message "sieve: Reconnecting with stream `%s'..."
+ sieve-manage-stream)
+ (sieve-manage-close buffer)
+ (if (sieve-manage-open-1 buffer)
+ (message "sieve: Reconnecting with stream `%s'...done"
+ sieve-manage-stream)
+ (message "sieve: Reconnecting with stream `%s'...failed"
+ sieve-manage-stream))
+ (setq sieve-manage-capability nil))
+ (if (sieve-manage-opened buffer)
+ ;; Choose authenticator
+ (when (and (null sieve-manage-auth)
+ (not (eq sieve-manage-state 'auth)))
+ (let ((auths sieve-manage-authenticators))
+ (while (setq auth (pop auths))
+ (if (funcall (nth 1 (assq
+ auth
+ sieve-manage-authenticator-alist))
+ buffer)
+ (setq sieve-manage-auth auth
+ auths nil)))
+ (unless sieve-manage-auth
+ (error "Couldn't figure out authenticator for server"))))))
+ (message "sieve: Connecting to %s...failed" sieve-manage-server))
+ (when (sieve-manage-opened buffer)
+ (sieve-manage-erase)
+ buffer)))
+
+(defun sieve-manage-opened (&optional buffer)
+ "Return non-nil if connection to managesieve server in BUFFER is open.
+If BUFFER is nil then the current buffer is used."
+ (and (setq buffer (get-buffer (or buffer (current-buffer))))
+ (buffer-live-p buffer)
+ (with-current-buffer buffer
+ (and sieve-manage-process
+ (memq (process-status sieve-manage-process) '(open run))))))
+
+(defun sieve-manage-close (&optional buffer)
+ "Close connection to managesieve server in BUFFER.
+If BUFFER is nil, the current buffer is used."
+ (with-current-buffer (or buffer (current-buffer))
+ (when (sieve-manage-opened)
+ (sieve-manage-send "LOGOUT")
+ (sit-for 1))
+ (when (and sieve-manage-process
+ (memq (process-status sieve-manage-process) '(open run)))
+ (delete-process sieve-manage-process))
+ (setq sieve-manage-process nil)
+ (sieve-manage-erase)
+ t))
+
+(defun sieve-manage-authenticate (&optional user passwd buffer)
+ "Authenticate to server in BUFFER, using current buffer if nil.
+It uses the authenticator specified when opening the server. If the
+authenticator requires username/passwords, they are queried from the
+user and optionally stored in the buffer. If USER and/or PASSWD is
+specified, the user will not be questioned and the username and/or
+password is remembered in the buffer."
+ (with-current-buffer (or buffer (current-buffer))
+ (if (not (eq sieve-manage-state 'nonauth))
+ (eq sieve-manage-state 'auth)
+ (make-variable-buffer-local 'sieve-manage-username)
+ (make-variable-buffer-local 'sieve-manage-password)
+ (if user (setq sieve-manage-username user))
+ (if passwd (setq sieve-manage-password passwd))
+ (if (funcall (nth 2 (assq sieve-manage-auth
+ sieve-manage-authenticator-alist)) buffer)
+ (setq sieve-manage-state 'auth)))))
+
+(defun sieve-manage-capability (&optional name value buffer)
+ (with-current-buffer (or buffer (current-buffer))
+ (if (null name)
+ sieve-manage-capability
+ (if (null value)
+ (nth 1 (assoc name sieve-manage-capability))
+ (when (string-match value (nth 1 (assoc name sieve-manage-capability)))
+ (nth 1 (assoc name sieve-manage-capability)))))))
+
+(defun sieve-manage-listscripts (&optional buffer)
+ (with-current-buffer (or buffer (current-buffer))
+ (sieve-manage-send "LISTSCRIPTS")
+ (sieve-manage-parse-listscripts)))
+
+(defun sieve-manage-havespace (name size &optional buffer)
+ (with-current-buffer (or buffer (current-buffer))
+ (sieve-manage-send (format "HAVESPACE \"%s\" %s" name size))
+ (sieve-manage-parse-okno)))
+
+(eval-and-compile
+ (if (fboundp 'string-bytes)
+ (defalias 'sieve-string-bytes 'string-bytes)
+ (defalias 'sieve-string-bytes 'length)))
+
+(defun sieve-manage-putscript (name content &optional buffer)
+ (with-current-buffer (or buffer (current-buffer))
+ (sieve-manage-send (format "PUTSCRIPT \"%s\" {%d+}%s%s" name
+ (sieve-string-bytes content)
+ sieve-manage-client-eol content))
+ (sieve-manage-parse-okno)))
+
+(defun sieve-manage-getscript (name output-buffer &optional buffer)
+ (with-current-buffer (or buffer (current-buffer))
+ (sieve-manage-send (format "GETSCRIPT \"%s\"" name))
+ (let ((script (sieve-manage-parse-string)))
+ (sieve-manage-parse-crlf)
+ (with-current-buffer output-buffer
+ (insert script))
+ (sieve-manage-parse-okno))))
+
+(defun sieve-manage-setactive (name &optional buffer)
+ (with-current-buffer (or buffer (current-buffer))
+ (sieve-manage-send (format "SETACTIVE \"%s\"" name))
+ (sieve-manage-parse-okno)))
+
+;; Protocol parsing routines
+
+(defun sieve-manage-ok-p (rsp)
+ (string= (downcase (or (car-safe rsp) "")) "ok"))
+
+(defsubst sieve-manage-forward ()
+ (or (eobp) (forward-char)))
+
+(defun sieve-manage-is-okno ()
+ (when (looking-at (concat
+ "^\\(OK\\|NO\\)\\( (\\([^)]+\\))\\)?\\( \\(.*\\)\\)?"
+ sieve-manage-server-eol))
+ (list (match-string 1) (match-string 3) (match-string 5))))
+
+(defun sieve-manage-parse-okno ()
+ (let (rsp)
+ (while (null rsp)
+ (accept-process-output (get-buffer-process (current-buffer)) 1)
+ (goto-char (point-min))
+ (setq rsp (sieve-manage-is-okno)))
+ (sieve-manage-erase)
+ rsp))
+
+(defun sieve-manage-parse-capability-1 ()
+ "Accept a managesieve greeting."
+ (let (str)
+ (while (setq str (sieve-manage-is-string))
+ (if (eq (char-after) ? )
+ (progn
+ (sieve-manage-forward)
+ (push (list str (sieve-manage-is-string))
+ sieve-manage-capability))
+ (push (list str) sieve-manage-capability))
+ (forward-line)))
+ (when (re-search-forward (concat "^OK" sieve-manage-server-eol) nil t)
+ (setq sieve-manage-state 'nonauth)))
+
+(defalias 'sieve-manage-parse-greeting-1 'sieve-manage-parse-capability-1)
+
+(defun sieve-manage-is-string ()
+ (cond ((looking-at "\"\\([^\"]+\\)\"")
+ (prog1
+ (match-string 1)
+ (goto-char (match-end 0))))
+ ((looking-at (concat "{\\([0-9]+\\)}" sieve-manage-server-eol))
+ (let ((pos (match-end 0))
+ (len (string-to-number (match-string 1))))
+ (if (< (point-max) (+ pos len))
+ nil
+ (goto-char (+ pos len))
+ (buffer-substring pos (+ pos len)))))))
+
+(defun sieve-manage-parse-string ()
+ (let (rsp)
+ (while (null rsp)
+ (accept-process-output (get-buffer-process (current-buffer)) 1)
+ (goto-char (point-min))
+ (setq rsp (sieve-manage-is-string)))
+ (sieve-manage-erase (point))
+ rsp))
+
+(defun sieve-manage-parse-crlf ()
+ (when (looking-at sieve-manage-server-eol)
+ (sieve-manage-erase (match-end 0))))
+
+(defun sieve-manage-parse-listscripts ()
+ (let (tmp rsp data)
+ (while (null rsp)
+ (while (null (or (setq rsp (sieve-manage-is-okno))
+ (setq tmp (sieve-manage-is-string))))
+ (accept-process-output (get-buffer-process (current-buffer)) 1)
+ (goto-char (point-min)))
+ (when tmp
+ (while (not (looking-at (concat "\\( ACTIVE\\)?"
+ sieve-manage-server-eol)))
+ (accept-process-output (get-buffer-process (current-buffer)) 1)
+ (goto-char (point-min)))
+ (if (match-string 1)
+ (push (cons 'active tmp) data)
+ (push tmp data))
+ (goto-char (match-end 0))
+ (setq tmp nil)))
+ (sieve-manage-erase)
+ (if (sieve-manage-ok-p rsp)
+ data
+ rsp)))
+
+(defun sieve-manage-send (cmdstr)
+ (setq cmdstr (concat cmdstr sieve-manage-client-eol))
+ (and sieve-manage-log
+ (with-current-buffer (get-buffer-create sieve-manage-log)
+ (sieve-manage-disable-multibyte)
+ (buffer-disable-undo)
+ (goto-char (point-max))
+ (insert cmdstr)))
+ (process-send-string sieve-manage-process cmdstr))
+
+(provide 'sieve-manage)
+
+;; sieve-manage.el ends here
--- /dev/null
+;;; sieve-mode.el --- Sieve code editing commands for Emacs
+;; Copyright (C) 2001 Free Software Foundation, Inc.
+
+;; Author: Simon Josefsson <simon@josefsson.org>
+
+;; This file is not part of GNU Emacs, but the same permissions apply.
+
+;; GNU Emacs 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 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; This file contain editing mode functions and font-lock support for
+;; editing Sieve scripts. It sets up C-mode with support for
+;; sieve-style #-comments and a lightly hacked syntax table. It was
+;; strongly influenced by awk-mode.el.
+;;
+;; Put something similar to the following in your .emacs to use this file:
+;;
+;; (load "~/lisp/sieve")
+;; (setq auto-mode-alist (cons '("\\.siv\\'" . sieve-mode) auto-mode-alist))
+;;
+;; References:
+;;
+;; RFC 3028,
+;; "Sieve: A Mail Filtering Language",
+;; by Tim Showalter.
+;;
+;; Release history:
+;;
+;; 2001-03-02 version 1.0 posted to gnu.emacs.sources
+;; version 1.1 change file extension into ".siv" (official one)
+;; added keymap and menubar to hook into sieve-manage
+;; 2001-10-31 version 1.2 committed to Oort Gnus
+;;
+;; $Id: sieve-mode.el,v 1.1.1.1 2002-01-06 22:11:34 yamaoka Exp $
+
+;;; Code:
+
+(autoload 'sieve-manage "sieve-manage")
+(autoload 'sieve-upload "sieve-manage")
+(require 'easymenu)
+(eval-when-compile
+ (require 'font-lock))
+
+(defgroup sieve nil
+ "Sieve."
+ :group 'languages)
+
+(defcustom sieve-mode-hook nil
+ "Hook run in sieve mode buffers."
+ :group 'sieve
+ :type 'hook)
+
+;; Font-lock
+
+(defvar sieve-control-commands-face 'sieve-control-commands-face
+ "Face name used for Sieve Control Commands.")
+
+(defface sieve-control-commands-face
+ '((((type tty) (class color)) (:foreground "blue" :weight light))
+ (((class grayscale) (background light)) (:foreground "LightGray" :bold t))
+ (((class grayscale) (background dark)) (:foreground "DimGray" :bold t))
+ (((class color) (background light)) (:foreground "Orchid"))
+ (((class color) (background dark)) (:foreground "LightSteelBlue"))
+ (t (:bold t)))
+ "Face used for Sieve Control Commands.")
+
+(defvar sieve-action-commands-face 'sieve-action-commands-face
+ "Face name used for Sieve Action Commands.")
+
+(defface sieve-action-commands-face
+ '((((type tty) (class color)) (:foreground "blue" :weight bold))
+ (((class color) (background light)) (:foreground "Blue"))
+ (((class color) (background dark)) (:foreground "LightSkyBlue"))
+ (t (:inverse-video t :bold t)))
+ "Face used for Sieve Action Commands.")
+
+(defvar sieve-test-commands-face 'sieve-test-commands-face
+ "Face name used for Sieve Test Commands.")
+
+(defface sieve-test-commands-face
+ '((((type tty) (class color)) (:foreground "magenta"))
+ (((class grayscale) (background light))
+ (:foreground "LightGray" :bold t :underline t))
+ (((class grayscale) (background dark))
+ (:foreground "Gray50" :bold t :underline t))
+ (((class color) (background light)) (:foreground "CadetBlue"))
+ (((class color) (background dark)) (:foreground "Aquamarine"))
+ (t (:bold t :underline t)))
+ "Face used for Sieve Test Commands.")
+
+(defvar sieve-tagged-arguments-face 'sieve-tagged-arguments-face
+ "Face name used for Sieve Tagged Arguments.")
+
+(defface sieve-tagged-arguments-face
+ '((((type tty) (class color)) (:foreground "cyan" :weight bold))
+ (((class grayscale) (background light)) (:foreground "LightGray" :bold t))
+ (((class grayscale) (background dark)) (:foreground "DimGray" :bold t))
+ (((class color) (background light)) (:foreground "Purple"))
+ (((class color) (background dark)) (:foreground "Cyan"))
+ (t (:bold t)))
+ "Face used for Sieve Tagged Arguments.")
+
+
+(defconst sieve-font-lock-keywords
+ (eval-when-compile
+ (list
+ ;; control commands
+ (cons (regexp-opt '("require" "if" "else" "elsif" "stop"))
+ 'sieve-control-commands-face)
+ ;; action commands
+ (cons (regexp-opt '("fileinto" "redirect" "reject" "keep" "discard"))
+ 'sieve-action-commands-face)
+ ;; test commands
+ (cons (regexp-opt '("address" "allof" "anyof" "exists" "false"
+ "true" "header" "not" "size" "envelope"))
+ 'sieve-test-commands-face)
+ (cons "\\Sw+:\\sw+"
+ 'sieve-tagged-arguments-face))))
+
+;; Syntax table
+
+(defvar sieve-mode-syntax-table nil
+ "Syntax table in use in sieve-mode buffers.")
+
+(if sieve-mode-syntax-table
+ ()
+ (setq sieve-mode-syntax-table (make-syntax-table))
+ (modify-syntax-entry ?\\ "\\" sieve-mode-syntax-table)
+ (modify-syntax-entry ?\n "> " sieve-mode-syntax-table)
+ (modify-syntax-entry ?\f "> " sieve-mode-syntax-table)
+ (modify-syntax-entry ?\# "< " sieve-mode-syntax-table)
+ (modify-syntax-entry ?/ "." sieve-mode-syntax-table)
+ (modify-syntax-entry ?* "." sieve-mode-syntax-table)
+ (modify-syntax-entry ?+ "." sieve-mode-syntax-table)
+ (modify-syntax-entry ?- "." sieve-mode-syntax-table)
+ (modify-syntax-entry ?= "." sieve-mode-syntax-table)
+ (modify-syntax-entry ?% "." sieve-mode-syntax-table)
+ (modify-syntax-entry ?< "." sieve-mode-syntax-table)
+ (modify-syntax-entry ?> "." sieve-mode-syntax-table)
+ (modify-syntax-entry ?& "." sieve-mode-syntax-table)
+ (modify-syntax-entry ?| "." sieve-mode-syntax-table)
+ (modify-syntax-entry ?_ "_" sieve-mode-syntax-table)
+ (modify-syntax-entry ?\' "\"" sieve-mode-syntax-table))
+
+;; Key map definition
+
+(defvar sieve-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map "\C-c\C-l" 'sieve-upload)
+ (define-key map "\C-c\C-m" 'sieve-manage)
+ map)
+ "Key map used in sieve mode.")
+
+;; Menu definition
+
+(defvar sieve-mode-menu nil
+ "Menubar used in sieve mode.")
+
+;; Code for Sieve editing mode.
+
+;;;###autoload
+(define-derived-mode sieve-mode c-mode "Sieve"
+ "Major mode for editing Sieve code.
+This is much like C mode except for the syntax of comments. Its keymap
+inherits from C mode's and it has the same variables for customizing
+indentation. It has its own abbrev table and its own syntax table.
+
+Turning on Sieve mode runs `sieve-mode-hook'."
+ (set (make-local-variable 'paragraph-start) (concat "$\\|" page-delimiter))
+ (set (make-local-variable 'paragraph-separate) paragraph-start)
+ (set (make-local-variable 'comment-start) "#")
+ (set (make-local-variable 'comment-end) "")
+ ;;(set (make-local-variable 'comment-start-skip) "\\(^\\|\\s-\\);?#+ *")
+ (set (make-local-variable 'comment-start-skip) "#+ *")
+ (unless (featurep 'xemacs)
+ (set (make-local-variable 'font-lock-defaults)
+ '(sieve-font-lock-keywords nil nil ((?_ . "w")))))
+ (easy-menu-add-item nil nil sieve-mode-menu))
+
+;; Menu
+
+(easy-menu-define sieve-mode-menu sieve-mode-map
+ "Sieve Menu."
+ '("Sieve"
+ ["Upload script" sieve-upload t]
+ ["Manage scripts on server" sieve-manage t]))
+
+(provide 'sieve-mode)
+
+;; sieve-mode.el ends here
--- /dev/null
+;;; sieve.el --- Utilities to manage sieve scripts
+;; Copyright (C) 2001 Free Software Foundation, Inc.
+
+;; Author: Simon Josefsson <simon@josefsson.org>
+
+;; This file is not part of GNU Emacs, but the same permissions apply.
+
+;; GNU Emacs 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 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; This file contain utilities to facilate upload, download and
+;; general management of sieve scripts. Currently only the
+;; Managesieve protocol is supported (using sieve-manage.el), but when
+;; (useful) alternatives become available, they might be supported as
+;; well.
+;;
+;; The cursor navigation was inspired by biff-mode by Franklin Lee.
+;;
+;; Release history:
+;;
+;; 2001-10-31 Committed to Oort Gnus.
+;;
+;; $Id: sieve.el,v 1.1.1.1 2002-01-06 22:11:34 yamaoka Exp $
+;;
+;; Todo:
+;;
+;; * Namespace? This file contains `sieve-manage' and
+;; `sieve-manage-mode', but there is a sieve-manage.el file as well.
+;; Can't think of a good solution though, this file need a *-mode,
+;; and naming it `sieve-mode' would collide with sieve-mode.el. One
+;; solution would be to come up with some better name that this file
+;; can use that doesn't have the managesieve specific "manage" in
+;; it. sieve-dired? i dunno. we could copy all off sieve.el into
+;; sieve-manage.el too, but I'd like to separate the interface from
+;; the protocol implementation since the backends are likely to
+;; change (well).
+;;
+;; * Define servers? We could have a customize buffer to create a server,
+;; with authentication/stream/etc parameters, much like Gnus, and then
+;; only use names of defined servers when interacting with M-x sieve-*.
+;; Right now you can't use STARTTLS, which sieve-manage.el provides
+
+;;; Code:
+
+(require 'sieve-manage)
+(require 'sieve-mode)
+
+;; User customizable variables:
+
+(defgroup sieve nil
+ "Manage sieve scripts."
+ :group 'tools)
+
+(defcustom sieve-new-script "<new script>"
+ "Name of name script indicator."
+ :type 'string
+ :group 'sieve)
+
+(defcustom sieve-buffer "*sieve*"
+ "Name of sieve management buffer."
+ :type 'string
+ :group 'sieve)
+
+(defcustom sieve-template "\
+require \"fileinto\";
+
+# Example script (remove comment character '#' to make it effective!):
+#
+# if header :contains \"from\" \"coyote\" {
+# discard;
+# } elsif header :contains [\"subject\"] [\"$$$\"] {
+# discard;
+# } else {
+# fileinto \"INBOX\";
+# }
+"
+ "Template sieve script."
+ :type 'string
+ :group 'sieve)
+
+;; Internal variables:
+
+(defvar sieve-manage-buffer nil)
+(defvar sieve-buffer-header-end nil)
+
+;; Sieve-manage mode:
+
+(defvar sieve-manage-mode-map nil
+ "Keymap for `sieve-manage-mode'.")
+
+(if sieve-manage-mode-map
+ ()
+ (setq sieve-manage-mode-map (make-sparse-keymap))
+ (suppress-keymap sieve-manage-mode-map)
+ ;; various
+ (define-key sieve-manage-mode-map "?" 'sieve-help)
+ (define-key sieve-manage-mode-map "h" 'sieve-help)
+ (define-key sieve-manage-mode-map "q" 'sieve-bury-buffer)
+ ;; activating
+ (define-key sieve-manage-mode-map "m" 'sieve-activate)
+ (define-key sieve-manage-mode-map "u" 'sieve-deactivate)
+ (define-key sieve-manage-mode-map "\M-\C-?" 'sieve-deactivate-all)
+ ;; navigation keys
+ (define-key sieve-manage-mode-map "\C-p" 'sieve-prev-line)
+ (define-key sieve-manage-mode-map [up] 'sieve-prev-line)
+ (define-key sieve-manage-mode-map "\C-n" 'sieve-next-line)
+ (define-key sieve-manage-mode-map [down] 'sieve-next-line)
+ (define-key sieve-manage-mode-map " " 'sieve-next-line)
+ (define-key sieve-manage-mode-map "n" 'sieve-next-line)
+ (define-key sieve-manage-mode-map "p" 'sieve-prev-line)
+ (define-key sieve-manage-mode-map "\C-m" 'sieve-edit-script)
+ (define-key sieve-manage-mode-map "f" 'sieve-edit-script)
+ (define-key sieve-manage-mode-map "o" 'sieve-edit-script-other-window)
+ (define-key sieve-manage-mode-map "r" 'sieve-remove)
+ (define-key sieve-manage-mode-map [mouse-2] 'sieve-edit-script)
+ (define-key sieve-manage-mode-map [(down-mouse-3)] 'sieve-menu))
+
+(define-derived-mode sieve-manage-mode fundamental-mode "SIEVE"
+ "Mode used for sieve script management."
+ (setq mode-name "SIEVE")
+ (buffer-disable-undo (current-buffer))
+ (setq truncate-lines t))
+
+(put 'sieve-manage-mode 'mode-class 'special)
+
+(easy-menu-define sieve-manage-mode-menu sieve-manage-mode-map
+ "Sieve Menu."
+ '("Manage Sieve"
+ ["Edit script" sieve-edit-script t]
+ ["Activate script" sieve-activate t]
+ ["Deactivate script" sieve-deactivate t]))
+
+;; This is necessary to allow correct handling of \\[cvs-mode-diff-map]
+;; in substitute-command-keys.
+;(fset 'sieve-manage-mode-map sieve-manage-mode-map)
+
+;; Commands used in sieve-manage mode:
+
+(defun sieve-activate (&optional pos)
+ (interactive "d")
+ (let ((name (sieve-script-at-point)) err)
+ (unless name
+ (error "No sieve script at point"))
+ (setq err (sieve-manage-setactive name sieve-manage-buffer))
+ (if (sieve-manage-ok-p err)
+ (message "Script %s activated." name)
+ (message "Failed to activate script %s: %s" name (nth 2 err)))
+ (sieve-refresh-scriptlist)))
+
+(defun sieve-edit-script (&optional pos)
+ (interactive "d")
+ (let ((name (sieve-script-at-point)))
+ (unless name
+ (error "No sieve script at point"))
+ (if (not (string-equal name sieve-new-script))
+ (let ((newbuf (generate-new-buffer name))
+ err)
+ (setq err (sieve-manage-getscript name newbuf sieve-manage-buffer))
+ (switch-to-buffer newbuf)
+ (unless (sieve-manage-ok-p err)
+ (error "Sieve download failed: %s" err)))
+ (switch-to-buffer (get-buffer-create "template.siv"))
+ (insert sieve-template))
+ (sieve-mode)
+ (message "Press C-c C-l to upload script to server.")))
+
+(defun sieve-next-line (&optional arg)
+ (interactive)
+ (unless arg
+ (setq arg 1))
+ (if (save-excursion
+ (forward-line arg)
+ (sieve-script-at-point))
+ (sieve-change-region
+ (forward-line arg))
+ (message "End of list")))
+
+(defun sieve-prev-line (&optional arg)
+ (interactive)
+ (unless arg
+ (setq arg -1))
+ (if (save-excursion
+ (forward-line arg)
+ (sieve-script-at-point))
+ (sieve-change-region
+ (forward-line arg))
+ (message "Beginning of list")))
+
+(defun sieve-help ()
+ "Display help for various sieve commands."
+ (interactive)
+ (if (eq last-command 'sieve-help)
+ ;; would need minor-mode for log-edit-mode
+ (describe-function 'sieve-mode)
+ (message (substitute-command-keys
+ "`\\[sieve-help]':help `\\[cvs-mode-add]':add `\\[sieve-remove]':remove"))))
+
+(defun sieve-bury-buffer (buf &optional mainbuf)
+ "Hide the buffer BUF that was temporarily popped up.
+BUF is assumed to be a temporary buffer used from the buffer MAINBUF."
+ (interactive (list (current-buffer)))
+ (save-current-buffer
+ (let ((win (if (eq buf (window-buffer (selected-window))) (selected-window)
+ (get-buffer-window buf t))))
+ (when win
+ (if (window-dedicated-p win)
+ (condition-case ()
+ (delete-window win)
+ (error (iconify-frame (window-frame win))))
+ (if (and mainbuf (get-buffer-window mainbuf))
+ (delete-window win)))))
+ (with-current-buffer buf
+ (bury-buffer (unless (and (eq buf (window-buffer (selected-window)))
+ (not (window-dedicated-p (selected-window))))
+ buf)))
+ (when mainbuf
+ (let ((mainwin (or (get-buffer-window mainbuf)
+ (get-buffer-window mainbuf 'visible))))
+ (when mainwin (select-window mainwin))))))
+
+;; Create buffer:
+
+(defun sieve-setup-buffer (server port)
+ (setq buffer-read-only nil)
+ (erase-buffer)
+ (buffer-disable-undo)
+ (insert "\
+Server : " server ":" (or port "2000") "
+
+")
+ (set (make-local-variable 'sieve-buffer-header-end)
+ (point-max)))
+
+(defun sieve-script-at-point (&optional pos)
+ "Return name of sieve script at point POS, or nil."
+ (interactive "d")
+ (get-char-property (or pos (point)) 'script-name))
+
+(defmacro sieve-change-region (&rest body)
+ "Turns off sieve-region before executing BODY, then re-enables it after.
+Used to bracket operations which move point in the sieve-buffer."
+ `(progn
+ (sieve-highlight nil)
+ ,@body
+ (sieve-highlight t)))
+(put 'sieve-change-region 'lisp-indent-function 0)
+
+(eval-and-compile
+ (defalias 'sieve-make-overlay (if (fboundp 'make-overlay)
+ 'make-overlay
+ 'make-extent))
+ (defalias 'sieve-overlay-put (if (fboundp 'overlay-put)
+ 'overlay-put
+ 'set-extent-property))
+ (defalias 'sieve-overlays-at (if (fboundp 'overlays-at)
+ 'overlays-at
+ 'extents-at)))
+
+(defun sieve-highlight (on)
+ "Turn ON or off highlighting on the current language overlay."
+ (sieve-overlay-put (car (sieve-overlays-at (point)))
+ 'face (if on 'highlight 'default)))
+
+(defun sieve-insert-scripts (scripts)
+ "Format and insert LANGUAGE-LIST strings into current buffer at point."
+ (while scripts
+ (let ((p (point))
+ (ext nil)
+ (script (pop scripts)))
+ (if (consp script)
+ (insert (format " ACTIVE %s" (cdr script)))
+ (insert (format " %s" script)))
+ (setq ext (sieve-make-overlay p (point)))
+ (sieve-overlay-put ext 'mouse-face 'highlight)
+ (sieve-overlay-put ext 'script-name (if (consp script)
+ (cdr script)
+ script))
+ (insert "\n"))))
+
+(defun sieve-open-server (server &optional port)
+ ;; open server
+ (set (make-local-variable 'sieve-manage-buffer)
+ (sieve-manage-open server))
+ ;; authenticate
+ (sieve-manage-authenticate nil nil sieve-manage-buffer))
+
+(defun sieve-refresh-scriptlist ()
+ (interactive)
+ (with-current-buffer sieve-buffer
+ (setq buffer-read-only nil)
+ (delete-region (or sieve-buffer-header-end (point-max)) (point-max))
+ (goto-char (point-max))
+ ;; get list of script names and print them
+ (let ((scripts (sieve-manage-listscripts sieve-manage-buffer)))
+ (if (null scripts)
+ (insert (format (concat "No scripts on server, press RET on %s to "
+ "create a new script.\n") sieve-new-script))
+ (insert (format (concat "%d script%s on server, press RET on a script "
+ "name edits it, or\npress RET on %s to create "
+ "a new script.\n") (length scripts)
+ (if (eq (length scripts) 1) "" "s")
+ sieve-new-script)))
+ (save-excursion
+ (sieve-insert-scripts (list sieve-new-script))
+ (sieve-insert-scripts scripts)))
+ (sieve-highlight t)
+ (setq buffer-read-only t)))
+
+;;;###autoload
+(defun sieve-manage (server &optional port)
+ (interactive "sServer: ")
+ (switch-to-buffer (get-buffer-create sieve-buffer))
+ (sieve-manage-mode)
+ (sieve-setup-buffer server port)
+ (if (sieve-open-server server port)
+ (sieve-refresh-scriptlist)
+ (message "Could not open server %s" server)))
+
+;;;###autoload
+(defun sieve-upload (&optional name)
+ (interactive)
+ (unless name
+ (setq name (buffer-name)))
+ (when (or (get-buffer sieve-buffer) (call-interactively 'sieve-manage))
+ (let ((script (buffer-string)) err)
+ (with-current-buffer (get-buffer sieve-buffer)
+ (setq err (sieve-manage-putscript name script sieve-manage-buffer))
+ (if (sieve-manage-ok-p err)
+ (message (concat "Sieve upload done. Use `C-c RET' to manage scripts."))
+ (message "Sieve upload failed: %s" (nth 2 err)))))))
+
+(provide 'sieve)
+
+;; sieve.el ends here
;;; smiley-ems.el --- displaying smiley faces
-;; Copyright (C) 2000 Free Software Foundation, Inc.
+;; Copyright (C) 2000, 2001 Free Software Foundation, Inc.
;; Author: Dave Love <fx@gnu.org>
;; Keywords: news mail multimedia
;; The XEmacs version has a baroque, if not rococo, set of these.
(defcustom smiley-regexp-alist
- ;; Perhaps :-) should be distinct -- it does appear in the Jargon File.
- '(("\\([:;]-?)\\)\\W" 1 "smile.pbm")
- ("\\(:-[/\\]\\)\\W" 1 "wry.pbm")
- ("\\(:-[({]\\)\\W" 1 "frown.pbm"))
+ '(("\\(:-?)\\)\\W" 1 "smile")
+ ("\\(;-?)\\)\\W" 1 "blink")
+ ("\\(:-]\\)\\W" 1 "forced")
+ ("\\(8-)\\)\\W" 1 "braindamaged")
+ ("\\(:-|\\)\\W" 1 "indifferent")
+ ("\\(:-[/\\]\\)\\W" 1 "wry")
+ ("\\(:-(\\)\\W" 1 "sad")
+ ("\\(:-{\\)\\W" 1 "frown"))
"*A list of regexps to map smilies to images.
The elements are (REGEXP MATCH FILE), where MATCH is the submatch in
-rgexp to replace with IMAGE. IMAGE is the name of a PBM file in
+regexp to replace with IMAGE. IMAGE is the name of a PBM file in
`smiley-data-directory'."
:type '(repeat (list regexp
(integer :tag "Regexp match number")
:initialize 'custom-initialize-default
:group 'smiley)
+(defcustom gnus-smiley-file-types
+ (let ((types (list "pbm")))
+ (when (gnus-image-type-available-p 'xpm)
+ (push "xpm" types))
+ types)
+ "*List of suffixes on picon file names to try."
+ :type '(repeat string)
+ :group 'smiley)
+
(defvar smiley-cached-regexp-alist nil)
(defun smiley-update-cache ()
- (dolist (elt smiley-regexp-alist)
- (let* ((data-directory smiley-data-directory)
- (image (find-image (list (list :type 'pbm
- :file (nth 2 elt)
- :ascent 'center)))))
- (if image
- (push (list (car elt) (cadr elt) image)
- smiley-cached-regexp-alist)))))
+ (dolist (elt (if (symbolp smiley-regexp-alist)
+ (symbol-value smiley-regexp-alist)
+ smiley-regexp-alist))
+ (let ((types gnus-smiley-file-types)
+ file type)
+ (while (and (not file)
+ (setq type (pop types)))
+ (unless (file-exists-p
+ (setq file (expand-file-name (concat (nth 2 elt) "." type)
+ smiley-data-directory)))
+ (setq file nil)))
+ (when type
+ (let ((image (find-image (list (list :type (intern type)
+ :file file
+ :ascent 'center)))))
+ (when image
+ (push (list (car elt) (cadr elt) image)
+ smiley-cached-regexp-alist)))))))
(defvar smiley-active nil
"Non-nil means smilies in the buffer will be displayed.")
;;;###autoload
(defun smiley-region (start end)
- "Replace in the region `smiley-regexp-alist' matches with corresponding images."
+ "Replace in the region `smiley-regexp-alist' matches with corresponding images.
+A list of images is returned."
(interactive "r")
(when (and (fboundp 'display-graphic-p)
(display-graphic-p))
(overlays-in start end))
(unless smiley-cached-regexp-alist
(smiley-update-cache))
+ (setq smiley-active t)
(save-excursion
(let ((beg (or start (point-min)))
- group overlay image)
+ group overlay image images)
(dolist (entry smiley-cached-regexp-alist)
(setq group (nth 1 entry)
image (nth 2 entry))
(goto-char beg)
(while (re-search-forward (car entry) end t)
(when image
- (setq overlay (make-overlay (match-beginning group)
- (match-end group)))
- (overlay-put overlay
- 'display `(when smiley-active ,@image))
- (overlay-put overlay 'mouse-face 'highlight)
- (overlay-put overlay 'smiley t)
- (overlay-put overlay
- 'help-echo "mouse-2: toggle smilies in buffer")
- (overlay-put overlay 'keymap smiley-mouse-map))))))
- (setq smiley-active t)))
+ (push image images)
+ (add-text-properties
+ (match-beginning group) (match-end group)
+ `(display ,image
+ mouse-face highlight
+ smiley t
+ help-echo "mouse-2: toggle smilies in buffer"
+ keymap smiley-mouse-map)))))
+ images))))
(defun smiley-toggle-buffer (&optional arg)
"Toggle displaying smiley faces.
"Display textual emoticaons (\"smilies\") as small graphical icons.
With arg, turn displaying on if and only if arg is positive."
(interactive "P")
- (save-excursion
- (article-goto-body)
- (smiley-region (point) (point-max))
- (if (and (numberp arg) (<= arg 0))
- (smiley-toggle-buffer arg))))
+ (gnus-with-article-buffer
+ (if (memq 'smiley gnus-article-wash-types)
+ (gnus-delete-images 'smiley)
+ (article-goto-body)
+ (let ((images (smiley-region (point) (point-max))))
+ (when images
+ (gnus-add-wash-type 'smiley)
+ (dolist (image images)
+ (gnus-add-image 'smiley image))))
+ (when (and (numberp arg)
+ (<= arg 0))
+ (smiley-toggle-buffer arg)))))
(provide 'smiley)
;;; smiley.el --- displaying smiley faces
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
;; Author: Wes Hardaker <hardaker@ece.ucdavis.edu>
;; The smilies were drawn by Joe Reiss <jreiss@vt.edu>.
+;;; Code:
+
(require 'cl)
(require 'custom)
:group 'gnus-visual)
;; FIXME: Where is the directory when using Emacs?
-(defcustom smiley-data-directory
+(defcustom smiley-data-directory
(if (featurep 'xemacs)
(message-xmas-find-glyph-directory "smilies")
"/usr/local/lib/xemacs/xemacs-packages/etc/smilies")
"Toggle smiley at given point.
Note -- this function hasn't been implemented yet."
(interactive "e")
- (error "This function hasn't been implemented yet.")
-)
+ (error "This function hasn't been implemented yet"))
(defun smiley-toggle-extents (e)
(interactive "e")
;; FIXME::
(defun smiley-toggle-extents-ems (e)
(interactive "e")
- (error "This function hasn't been implemented yet.")
-)
+ (error "This function hasn't been implemented yet"))
;;;###autoload
(defun smiley-buffer (&optional buffer st nd)
(dolist (overlay (overlays-in (or st (point-min))
(or nd (point-max))))
(when (overlay-get overlay 'smiley)
- (remove-text-properties (overlay-start overlay)
+ (remove-text-properties (overlay-start overlay)
(overlay-end overlay) '(display))
(delete-overlay overlay)))
(goto-char (or st (point-min)))
;; FIXME: make it work as the one in XEmacs.
(defun smiley-toggle-buffer-ems (&optional arg buffer st nd)
"Toggle displaying smiley faces.
-With arg, turn displaying on if and only if arg is positive."
+With arg, turn displaying on if and only if arg is positive."
(interactive "P")
(save-excursion
(when buffer
(dolist (overlay (overlays-in (or st (point-min))
(or nd (point-max))))
(when (overlay-get overlay 'smiley)
- (remove-text-properties (overlay-start overlay)
+ (remove-text-properties (overlay-start overlay)
(overlay-end overlay) '(display))
(setq found t)))
(unless found
;; PKCSx or similar, it's intended to perform common operations
;; done on messages encoded in these formats. The terminology chosen
;; reflect this.
+;;
+;; The home of this file is in Gnus CVS, but also available from
+;; http://josefsson.org/smime.html.
;;; Quick introduction:
;; environment variables to pass the password to OpenSSL, which is
;; slightly insecure. Hence a new todo: use a better -passin method.
;;
+;; Cache password for e.g. 1h
+;;
;; Suggestions and comments are appreciated, mail me at simon@josefsson.org.
-;; <rant>
+;; begin rant
;;
;; I would include pointers to introductory text on concepts used in
;; this library here, but the material I've read are so horrible I
;; Also, I'm not going to mention anything about the wonders of
;; cryptopolitics. Oops, I just did.
;;
-;; </rant>
+;; end rant
;;; Revision history:
-;; version 0 not released
+;; 2000-06-05 initial version, committed to Gnus CVS contrib/
+;; 2000-10-28 retrieve certificates via DNS CERT RRs
+;; 2001-10-14 posted to gnu.emacs.sources
;;; Code:
"S/MIME configuration.")
(defcustom smime-keys nil
- "Map mail addresses to a file containing Certificate (and private key).
-The file is assumed to be in PEM format and not encrypted."
+ "*Map mail addresses to a file containing Certificate (and private key).
+The file is assumed to be in PEM format. You can also associate additional
+certificates to be sent with every message to each address."
:type '(repeat (list (string :tag "Mail address")
- (file :tag "File name")))
+ (file :tag "File name")
+ (repeat :tag "Additional certificate files"
+ (file :tag "File name"))))
:group 'smime)
(defcustom smime-CA-directory nil
- "Directory containing certificates for CAs you trust.
+ "*Directory containing certificates for CAs you trust.
Directory should contain files (in PEM format) named to the X.509
hash of the certificate. This can be done using OpenSSL such as:
:group 'smime)
(defcustom smime-CA-file nil
- "Files containing certificates for CAs you trust.
+ "*Files containing certificates for CAs you trust.
File should contain certificates in PEM format."
:type '(choice (const :tag "none" nil)
file)
:group 'smime)
(defcustom smime-certificate-directory "~/Mail/certs/"
- "Directory containing other people's certificates.
+ "*Directory containing other people's certificates.
It should contain files named to the X.509 hash of the certificate,
and the files themself should be in PEM format."
;The S/MIME library provide simple functionality for fetching
(eq 0 (call-process "openssl" nil nil nil "version"))
(error nil))
"openssl")
- "Name of OpenSSL binary."
+ "*Name of OpenSSL binary."
:type 'string
:group 'smime)
;; OpenSSL option to select the encryption cipher
(defcustom smime-encrypt-cipher "-des3"
- "Cipher algorithm used for encryption."
+ "*Cipher algorithm used for encryption."
:type '(choice (const :tag "Triple DES" "-des3")
(const :tag "DES" "-des")
(const :tag "RC2 40 bits" "-rc2-40")
(const :tag "RC2 64 bits" "-rc2-64")
(const :tag "RC2 128 bits" "-rc2-128"))
:group 'smime)
-
+
(defcustom smime-dns-server nil
- "DNS server to query certificates from.
+ "*DNS server to query certificates from.
If nil, use system defaults."
:type '(choice (const :tag "System defaults")
string)
- :group 'dig)
+ :group 'smime)
(defvar smime-details-buffer "*OpenSSL output*")
+(eval-and-compile
+ (defalias 'smime-make-temp-file
+ (if (fboundp 'make-temp-file)
+ 'make-temp-file
+ (lambda (prefix &optional dir-flag) ;; Simple implementation
+ (expand-file-name
+ (make-temp-name prefix)
+ temporary-file-directory)))))
+
;; Password dialog function
(defun smime-ask-passphrase ()
(4 (message "OpenSSL: An error occurred decrypting or verifying the message.") nil)
(t (error "Unknown OpenSSL exitcode") nil)))
+(defun smime-make-certfiles (certfiles)
+ (if certfiles
+ (append (list "-certfile" (expand-file-name (car certfiles)))
+ (smime-make-certfiles (cdr certfiles)))))
+
;; Sign+encrypt region
-(defun smime-sign-region (b e keyfile)
- "Sign region with certified key in KEYFILE.
+(defun smime-sign-region (b e keyfiles)
+ "Sign region with certified key in KEYFILES.
If signing fails, the buffer is not modified. Region is assumed to
-have proper MIME tags. KEYFILE is expected to contain a PEM encoded
-private key and certificate."
- (let ((buffer (generate-new-buffer (generate-new-buffer-name " *smime*")))
- (passphrase (smime-ask-passphrase)))
+have proper MIME tags. KEYFILES is expected to contain a PEM encoded
+private key and certificate as its car, and a list of additional certificates
+to include in its caar."
+ (smime-new-details-buffer)
+ (let ((keyfile (car keyfiles))
+ (certfiles (and (cdr keyfiles) (cadr keyfiles)))
+ (buffer (generate-new-buffer (generate-new-buffer-name " *smime*")))
+ (passphrase (smime-ask-passphrase))
+ (tmpfile (smime-make-temp-file "smime")))
(if passphrase
(setenv "GNUS_SMIME_PASSPHRASE" passphrase))
(prog1
- (when (apply 'smime-call-openssl-region b e buffer "smime" "-sign"
- "-signer" (expand-file-name keyfile)
- (if passphrase
- (list "-passin" "env:GNUS_SMIME_PASSPHRASE")))
+ (when (prog1
+ (apply 'smime-call-openssl-region b e (list buffer tmpfile)
+ "smime" "-sign" "-signer" (expand-file-name keyfile)
+ (append
+ (smime-make-certfiles certfiles)
+ (if passphrase
+ (list "-passin" "env:GNUS_SMIME_PASSPHRASE"))))
+ (if passphrase
+ (setenv "GNUS_SMIME_PASSPHRASE" "" t))
+ (with-current-buffer smime-details-buffer
+ (insert-file-contents tmpfile)
+ (delete-file tmpfile)))
(delete-region b e)
- (insert-buffer buffer)
+ (insert-buffer-substring buffer)
+ (goto-char b)
(when (looking-at "^MIME-Version: 1.0$")
(delete-region (point) (progn (forward-line 1) (point))))
t)
- (if passphrase
- (setenv "GNUS_SMIME_PASSPHRASE" "" t))
- (with-current-buffer (get-buffer-create smime-details-buffer)
+ (with-current-buffer smime-details-buffer
(goto-char (point-max))
- (insert-buffer buffer))
+ (insert-buffer-substring buffer))
(kill-buffer buffer))))
(defun smime-encrypt-region (b e certfiles)
If encryption fails, the buffer is not modified. Region is assumed to
have proper MIME tags. CERTFILES is a list of filenames, each file
is expected to contain of a PEM encoded certificate."
- (let ((buffer (generate-new-buffer (generate-new-buffer-name " *smime*"))))
+ (smime-new-details-buffer)
+ (let ((buffer (generate-new-buffer (generate-new-buffer-name " *smime*")))
+ (tmpfile (smime-make-temp-file "smime")))
(prog1
- (when (apply 'smime-call-openssl-region b e buffer "smime" "-encrypt"
- smime-encrypt-cipher (mapcar 'expand-file-name certfiles))
+ (when (prog1
+ (apply 'smime-call-openssl-region b e (list buffer tmpfile)
+ "smime" "-encrypt" smime-encrypt-cipher
+ (mapcar 'expand-file-name certfiles))
+ (with-current-buffer smime-details-buffer
+ (insert-file-contents tmpfile)
+ (delete-file tmpfile)))
(delete-region b e)
- (insert-buffer buffer)
+ (insert-buffer-substring buffer)
+ (goto-char b)
(when (looking-at "^MIME-Version: 1.0$")
(delete-region (point) (progn (forward-line 1) (point))))
t)
- (with-current-buffer (get-buffer-create smime-details-buffer)
+ (with-current-buffer smime-details-buffer
(goto-char (point-max))
- (insert-buffer buffer))
+ (insert-buffer-substring buffer))
(kill-buffer buffer))))
;; Sign+encrypt buffer
(with-current-buffer (or buffer (current-buffer))
(smime-sign-region
(point-min) (point-max)
- (or keyfile
- (smime-get-key-by-email
- (completing-read "Sign using which signature? " smime-keys nil nil
- (and (listp (car-safe smime-keys))
- (caar smime-keys))))))))
+ (if keyfile
+ (list keyfile (smime-get-certfiles keyfile smime-keys))
+ (smime-get-key-by-email
+ (completing-read "Sign using which signature? " smime-keys nil nil
+ (and (listp (car-safe smime-keys))
+ (cdr smime-keys))))))))
(defun smime-encrypt-buffer (&optional certfiles buffer)
"S/MIME encrypt BUFFER for recipients specified in CERTFILES.
;; Verify+decrypt region
(defun smime-verify-region (b e)
- (let ((buffer (get-buffer-create smime-details-buffer))
- (CAs (cond (smime-CA-file
- (list "-CAfile" (expand-file-name smime-CA-file)))
- (smime-CA-directory
- (list "-CApath" (expand-file-name smime-CA-directory)))
- (t
- (error "No CA configured.")))))
- (with-current-buffer buffer
- (erase-buffer))
- (if (apply 'smime-call-openssl-region b e buffer "smime" "-verify"
- "-out" "/dev/null" CAs)
- (message "S/MIME message verified succesfully.")
- (message "S/MIME message NOT verified successfully.")
+ "Verify S/MIME message in region between B and E.
+Returns non-nil on success.
+Any details (stdout and stderr) are left in the buffer specified by
+`smime-details-buffer'."
+ (smime-new-details-buffer)
+ (let ((CAs (append (if smime-CA-file
+ (list "-CAfile"
+ (expand-file-name smime-CA-file)))
+ (if smime-CA-directory
+ (list "-CApath"
+ (expand-file-name smime-CA-directory))))))
+ (unless CAs
+ (error "No CA configured"))
+ (if (apply 'smime-call-openssl-region b e (list smime-details-buffer t)
+ "smime" "-verify" "-out" "/dev/null" CAs)
+ t
+ (insert-buffer-substring smime-details-buffer)
nil)))
(defun smime-noverify-region (b e)
- (let ((buffer (get-buffer-create smime-details-buffer)))
- (with-current-buffer buffer
- (erase-buffer))
- (if (apply 'smime-call-openssl-region b e buffer "smime" "-verify"
- "-noverify" "-out" '("/dev/null"))
- (message "S/MIME message verified succesfully.")
- (message "S/MIME message NOT verified successfully.")
- nil)))
+ "Verify integrity of S/MIME message in region between B and E.
+Returns non-nil on success.
+Any details (stdout and stderr) are left in the buffer specified by
+`smime-details-buffer'."
+ (smime-new-details-buffer)
+ (if (apply 'smime-call-openssl-region b e (list smime-details-buffer t)
+ "smime" "-verify" "-noverify" "-out" '("/dev/null"))
+ t
+ (insert-buffer-substring smime-details-buffer)
+ nil))
(defun smime-decrypt-region (b e keyfile)
- (let ((buffer (generate-new-buffer (generate-new-buffer-name "*smime*")))
- CAs (passphrase (smime-ask-passphrase)))
+ "Decrypt S/MIME message in region between B and E with key in KEYFILE.
+On success, replaces region with decrypted data and return non-nil.
+Any details (stderr on success, stdout and stderr on error) are left
+in the buffer specified by `smime-details-buffer'."
+ (smime-new-details-buffer)
+ (let ((buffer (generate-new-buffer (generate-new-buffer-name " *smime*")))
+ CAs (passphrase (smime-ask-passphrase))
+ (tmpfile (smime-make-temp-file "smime")))
(if passphrase
(setenv "GNUS_SMIME_PASSPHRASE" passphrase))
- (when (apply 'smime-call-openssl-region
- b e buffer "smime" "-decrypt"
- "-recip" (list keyfile)
- (if passphrase
- (list "-passin" "env:GNUS_SMIME_PASSPHRASE" )))
- )
- (if passphrase
- (setenv "GNUS_SMIME_PASSPHRASE" "" t))
- (with-current-buffer (get-buffer-create smime-details-buffer)
- (goto-char (point-max))
- (insert-buffer buffer))
- (kill-buffer buffer)))
+ (if (prog1
+ (apply 'smime-call-openssl-region b e
+ (list buffer tmpfile)
+ "smime" "-decrypt" "-recip" (expand-file-name keyfile)
+ (if passphrase
+ (list "-passin" "env:GNUS_SMIME_PASSPHRASE")))
+ (if passphrase
+ (setenv "GNUS_SMIME_PASSPHRASE" "" t))
+ (with-current-buffer smime-details-buffer
+ (insert-file-contents tmpfile)
+ (delete-file tmpfile)))
+ (progn
+ (delete-region b e)
+ (insert-buffer-substring buffer)
+ (kill-buffer buffer)
+ t)
+ (with-current-buffer smime-details-buffer
+ (insert-buffer-substring buffer))
+ (kill-buffer buffer)
+ (delete-region b e)
+ (insert-buffer-substring smime-details-buffer)
+ nil)))
;; Verify+Decrypt buffer
(defun smime-verify-buffer (&optional buffer)
"Verify integrity of S/MIME message in BUFFER.
-Uses current buffer if BUFFER is nil."
+Uses current buffer if BUFFER is nil. Returns non-nil on success.
+Any details (stdout and stderr) are left in the buffer specified by
+`smime-details-buffer'."
(interactive)
(with-current-buffer (or buffer (current-buffer))
(smime-verify-region (point-min) (point-max))))
(defun smime-noverify-buffer (&optional buffer)
"Verify integrity of S/MIME message in BUFFER.
-Uses current buffer if BUFFER is nil.
-Does NOT verify validity of certificate."
+Does NOT verify validity of certificate (only message integrity).
+Uses current buffer if BUFFER is nil. Returns non-nil on success.
+Any details (stdout and stderr) are left in the buffer specified by
+`smime-details-buffer'."
(interactive)
(with-current-buffer (or buffer (current-buffer))
(smime-noverify-region (point-min) (point-max))))
(defun smime-decrypt-buffer (&optional buffer keyfile)
"Decrypt S/MIME message in BUFFER using KEYFILE.
-Uses current buffer if BUFFER is nil, queries user of KEYFILE is nil."
+Uses current buffer if BUFFER is nil, and query user of KEYFILE if it's nil.
+On success, replaces data in buffer and return non-nil.
+Any details (stderr on success, stdout and stderr on error) are left
+in the buffer specified by `smime-details-buffer'."
(interactive)
(with-current-buffer (or buffer (current-buffer))
(smime-decrypt-region
;; Various operations
+(defun smime-new-details-buffer ()
+ (with-current-buffer (get-buffer-create smime-details-buffer)
+ (erase-buffer)))
+
(defun smime-pkcs7-region (b e)
"Convert S/MIME message between points B and E into a PKCS7 message."
- (let ((buffer (get-buffer-create smime-details-buffer)))
- (with-current-buffer buffer
- (erase-buffer))
- (when (smime-call-openssl-region b e buffer "smime" "-pk7out")
- (delete-region b e)
- (insert-buffer-substring buffer)
- t)))
+ (smime-new-details-buffer)
+ (when (smime-call-openssl-region b e smime-details-buffer "smime" "-pk7out")
+ (delete-region b e)
+ (insert-buffer-substring smime-details-buffer)
+ t))
(defun smime-pkcs7-certificates-region (b e)
"Extract any certificates enclosed in PKCS7 message between points B and E."
- (let ((buffer (get-buffer-create smime-details-buffer)))
- (with-current-buffer buffer
- (erase-buffer))
- (when (smime-call-openssl-region b e buffer "pkcs7" "-print_certs" "-text")
- (delete-region b e)
- (insert-buffer-substring buffer)
- t)))
+ (smime-new-details-buffer)
+ (when (smime-call-openssl-region
+ b e smime-details-buffer "pkcs7" "-print_certs" "-text")
+ (delete-region b e)
+ (insert-buffer-substring smime-details-buffer)
+ t))
(defun smime-pkcs7-email-region (b e)
"Get email addresses contained in certificate between points B and E.
A string or a list of strings is returned."
- (let ((buffer (get-buffer-create smime-details-buffer)))
- (with-current-buffer buffer
- (erase-buffer))
- (when (smime-call-openssl-region b e buffer "x509" "-email" "-noout")
- (delete-region b e)
- (insert-buffer-substring buffer)
- t)))
-
-(defalias 'smime-point-at-eol
- (if (fboundp 'point-at-eol)
- 'point-at-eol
- 'line-end-position))
+ (smime-new-details-buffer)
+ (when (smime-call-openssl-region
+ b e smime-details-buffer "x509" "-email" "-noout")
+ (delete-region b e)
+ (insert-buffer-substring smime-details-buffer)
+ t))
+
+;; Utility functions
+
+(defun smime-get-certfiles (keyfile keys)
+ (if keys
+ (let ((curkey (car keys))
+ (otherkeys (cdr keys)))
+ (if (string= keyfile (cadr curkey))
+ (caddr curkey)
+ (smime-get-certfiles keyfile otherkeys)))))
+
+(eval-and-compile
+ (defalias 'smime-point-at-eol
+ (if (fboundp 'point-at-eol)
+ 'point-at-eol
+ 'line-end-position)))
(defun smime-buffer-as-string-region (b e)
"Return each line in region between B and E as a list of strings."
;;; uudecode.el -- elisp native uudecode
-;; Copyright (c) 1998, 1999, 2000 Free Software Foundation, Inc.
+;; Copyright (c) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
;; Author: Shenghuo Zhu <zsh@cs.rochester.edu>
;; Keywords: uudecode news
;;; Commentary:
-;; Lots of codes are stolen from mm-decode.el, gnus-uu.el and
-;; base64.el
-
-;; This looks as though it could be made rather more efficient for
-;; internal working. Encoding could use a lookup table and decoding
-;; should presumably use a vector or list buffer for partial results
-;; rather than with-current-buffer. -- fx
-
-;; Only `uudecode-decode-region' should be advertised, and whether or
-;; not that uses a program should be customizable, but I guess it's
-;; too late now. -- fx
-
;;; Code:
+(autoload 'executable-find "executable")
+
(eval-when-compile (require 'cl))
(eval-and-compile
(defalias 'uudecode-char-int
(if (fboundp 'char-int)
'char-int
- 'identity))
-
- (if (featurep 'xemacs)
- (defalias 'uudecode-insert-char 'insert-char)
- (defun uudecode-insert-char (char &optional count ignored buffer)
- (if (or (null buffer) (eq buffer (current-buffer)))
- (insert-char char count)
- (with-current-buffer buffer
- (insert-char char count))))))
+ 'identity)))
(defcustom uudecode-decoder-program "uudecode"
"*Non-nil value should be a string that names a uu decoder.
:group 'gnus-extract
:type '(repeat string))
+(defcustom uudecode-use-external
+ (executable-find uudecode-decoder-program)
+ "*Use external uudecode program."
+ :group 'gnus-extract
+ :type 'boolean)
+
(defconst uudecode-alphabet "\040-\140")
(defconst uudecode-begin-line "^begin[ \t]+[0-7][0-7][0-7][ \t]+\\(.*\\)$")
(ignore-errors (or file-name (delete-file tempfile))))))
;;;###autoload
-(defun uudecode-decode-region (start end &optional file-name)
+(defun uudecode-decode-region-internal (start end &optional file-name)
"Uudecode region between START and END without using an external program.
If FILE-NAME is non-nil, save the result to FILE-NAME."
(interactive "r\nP")
- (let ((work-buffer nil)
- (done nil)
+ (let ((done nil)
(counter 0)
(remain 0)
(bits 0)
- (lim 0) inputpos
+ (lim 0) inputpos result
(non-data-chars (concat "^" uudecode-alphabet)))
- (unwind-protect
- (save-excursion
+ (save-excursion
+ (goto-char start)
+ (when (re-search-forward uudecode-begin-line nil t)
+ (cond ((null file-name))
+ ((stringp file-name))
+ (t
+ (setq file-name (expand-file-name
+ (read-file-name "File to Name:"
+ nil nil nil
+ (match-string 1))))))
+ (forward-line 1)
+ (skip-chars-forward non-data-chars end)
+ (while (not done)
+ (setq inputpos (point))
+ (setq remain 0 bits 0 counter 0)
+ (cond
+ ((> (skip-chars-forward uudecode-alphabet end) 0)
+ (setq lim (point))
+ (setq remain
+ (logand (- (uudecode-char-int (char-after inputpos)) 32)
+ 63))
+ (setq inputpos (1+ inputpos))
+ (if (= remain 0) (setq done t))
+ (while (and (< inputpos lim) (> remain 0))
+ (setq bits (+ bits
+ (logand
+ (-
+ (uudecode-char-int (char-after inputpos)) 32)
+ 63)))
+ (if (/= counter 0) (setq remain (1- remain)))
+ (setq counter (1+ counter)
+ inputpos (1+ inputpos))
+ (cond ((= counter 4)
+ (setq result (cons
+ (concat
+ (char-to-string (lsh bits -16))
+ (char-to-string (logand (lsh bits -8) 255))
+ (char-to-string (logand bits 255)))
+ result))
+ (setq bits 0 counter 0))
+ (t (setq bits (lsh bits 6)))))))
+ (cond
+ (done)
+ ((> 0 remain)
+ (error "uucode line ends unexpectly")
+ (setq done t))
+ ((and (= (point) end) (not done))
+ ;;(error "uucode ends unexpectly")
+ (setq done t))
+ ((= counter 3)
+ (setq result (cons
+ (concat
+ (char-to-string (logand (lsh bits -16) 255))
+ (char-to-string (logand (lsh bits -8) 255)))
+ result)))
+ ((= counter 2)
+ (setq result (cons
+ (char-to-string (logand (lsh bits -10) 255))
+ result))))
+ (skip-chars-forward non-data-chars end))
+ (if file-name
+ (let (default-enable-multibyte-characters)
+ (with-temp-file file-name
+ (insert (apply 'concat (nreverse result)))))
+ (or (markerp end) (setq end (set-marker (make-marker) end)))
(goto-char start)
- (when (re-search-forward uudecode-begin-line nil t)
- (cond ((null file-name))
- ((stringp file-name))
- (t
- (setq file-name (expand-file-name
- (read-file-name "File to Name:"
- nil nil nil
- (match-string 1))))))
- (setq work-buffer (generate-new-buffer " *uudecode-work*"))
- (forward-line 1)
- (skip-chars-forward non-data-chars end)
- (while (not done)
- (setq inputpos (point))
- (setq remain 0 bits 0 counter 0)
- (cond
- ((> (skip-chars-forward uudecode-alphabet end) 0)
- (setq lim (point))
- (setq remain
- (logand (- (uudecode-char-int (char-after inputpos)) 32)
- 63))
- (setq inputpos (1+ inputpos))
- (if (= remain 0) (setq done t))
- (while (and (< inputpos lim) (> remain 0))
- (setq bits (+ bits
- (logand
- (-
- (uudecode-char-int (char-after inputpos)) 32)
- 63)))
- (if (/= counter 0) (setq remain (1- remain)))
- (setq counter (1+ counter)
- inputpos (1+ inputpos))
- (cond ((= counter 4)
- (uudecode-insert-char
- (lsh bits -16) 1 nil work-buffer)
- (uudecode-insert-char
- (logand (lsh bits -8) 255) 1 nil work-buffer)
- (uudecode-insert-char (logand bits 255) 1 nil
- work-buffer)
- (setq bits 0 counter 0))
- (t (setq bits (lsh bits 6)))))))
- (cond
- (done)
- ((> 0 remain)
- (error "uucode line ends unexpectly")
- (setq done t))
- ((and (= (point) end) (not done))
- ;;(error "uucode ends unexpectly")
- (setq done t))
- ((= counter 3)
- (uudecode-insert-char (logand (lsh bits -16) 255) 1 nil
- work-buffer)
- (uudecode-insert-char (logand (lsh bits -8) 255) 1 nil
- work-buffer))
- ((= counter 2)
- (uudecode-insert-char (logand (lsh bits -10) 255) 1 nil
- work-buffer)))
- (skip-chars-forward non-data-chars end))
- (if file-name
- (save-excursion
- (set-buffer work-buffer)
- (write-file file-name))
- (or (markerp end) (setq end (set-marker (make-marker) end)))
- (goto-char start)
- (insert-buffer-substring work-buffer)
- (delete-region (point) end))))
- (and work-buffer (kill-buffer work-buffer)))))
+ (insert (apply 'concat (nreverse result)))
+ (delete-region (point) end))))))
+
+;;;###autoload
+(defun uudecode-decode-region (start end &optional file-name)
+ "Uudecode region between START and END.
+If FILE-NAME is non-nil, save the result to FILE-NAME."
+ (if uudecode-use-external
+ (uudecode-decode-region-external start end file-name)
+ (uudecode-decode-region-internal start end file-name)))
(provide 'uudecode)
(require 'gnus)
(require 'nnmail)
(require 'mm-util)
+(require 'mm-url)
(require 'mml)
(eval-when-compile
(ignore-errors
- (require 'w3)
(require 'url)
- (require 'url-cookie)
- (require 'w3-forms)
- (require 'nnweb)))
+ (require 'url-cookie)))
;; Report failure to find w3 at load time if appropriate.
(eval '(progn
- (require 'w3)
(require 'url)
- (require 'url-cookie)
- (require 'w3-forms)
- (require 'nnweb)))
+ (require 'url-cookie)))
;;;
(set (intern (concat "webmail-" (symbol-name var))) (cdr pair))
(set (intern (concat "webmail-" (symbol-name var))) nil)))))
-(defun webmail-encode-www-form-urlencoded (pairs)
- "Return PAIRS encoded for forms."
- (mapconcat
- (function
- (lambda (data)
- (concat (w3-form-encode-xwfu (car data)) "="
- (w3-form-encode-xwfu (cdr data)))))
- pairs "&"))
-
-(defun webmail-fetch-simple (url content)
- (let ((url-request-data content)
- (url-request-method "POST")
- (url-request-extra-headers
- '(("Content-type" . "application/x-www-form-urlencoded"))))
- (nnweb-insert url))
- t)
-
-(defun webmail-fetch-form (url pairs)
- (let ((url-request-data (webmail-encode-www-form-urlencoded pairs))
- (url-request-method "POST")
- (url-request-extra-headers
- '(("Content-type" . "application/x-www-form-urlencoded"))))
- (nnweb-insert url))
- t)
-
(defun webmail-eval (expr)
(cond
((consp expr)
(cond
((eq (car xurl) 'content)
(pop xurl)
- (webmail-fetch-simple (if (stringp (car xurl))
+ (mm-url-fetch-simple (if (stringp (car xurl))
(car xurl)
(apply 'format (webmail-eval (car xurl))))
(apply 'format (webmail-eval (cdr xurl)))))
((eq (car xurl) 'post)
(pop xurl)
- (webmail-fetch-form (car xurl) (webmail-eval (cdr xurl))))
+ (mm-url-fetch-form (car xurl) (webmail-eval (cdr xurl))))
(t
- (nnweb-insert (apply 'format (webmail-eval xurl)))))))
+ (mm-url-insert (apply 'format (webmail-eval xurl)))))))
(defun webmail-init ()
"Initialize buffers and such."
(let ((url (match-string 1)))
(erase-buffer)
(mm-with-unibyte-current-buffer
- (nnweb-insert url)))
+ (mm-url-insert url)))
(goto-char (point-min))))
(defun webmail-fetch (file subtype user password)
(message "Fetching mail #%d..." (setq n (1+ n)))
(erase-buffer)
(mm-with-unibyte-current-buffer
- (nnweb-insert (cdr item)))
+ (mm-url-insert (cdr item)))
(setq id (car item))
(if webmail-article-snarf
(funcall webmail-article-snarf file id))
(if (not (search-forward "</pre>" nil t))
(webmail-error "article@3.1"))
(delete-region (match-beginning 0) (point-max))
- (nnweb-remove-markup)
- (let ((w3-html-entities (cons '(nbsp . 32) w3-html-entities)))
- (nnweb-decode-entities))
+ (mm-url-remove-markup)
+ (mm-url-decode-entities-nbsp)
(goto-char (point-min))
(while (re-search-forward "\r\n?" nil t)
(replace-match "\n"))
(setq p (match-beginning 0))
(search-forward "</a>" nil t)
(delete-region p (match-end 0)))
- (nnweb-remove-markup)
- (let ((w3-html-entities (cons '(nbsp . 32) w3-html-entities)))
- (nnweb-decode-entities))
+ (mm-url-remove-markup)
+ (mm-url-decode-entities-nbsp)
(goto-char (point-min))
(delete-blank-lines)
(goto-char (point-min))
(delete-region p (match-end 0))
(save-excursion
(set-buffer (generate-new-buffer " *webmail-att*"))
- (nnweb-insert attachment)
+ (mm-url-insert attachment)
(push (current-buffer) webmail-buffer-list)
(setq bufname (buffer-name)))
(setq mime t)
(goto-char (match-end 0))
(if (looking-at "$") (forward-char))
(delete-region (point-min) (point))
- (nnweb-remove-markup)
- (let ((w3-html-entities (cons '(nbsp . 32) w3-html-entities)))
- (nnweb-decode-entities))
+ (mm-url-remove-markup)
+ (mm-url-decode-entities-nbsp)
nil)
(t
(setq mime t)
(setq p (match-beginning 0))
(search-forward "</a>" nil t)
(delete-region p (match-end 0)))
- (nnweb-remove-markup)
- (let ((w3-html-entities (cons '(nbsp . 32) w3-html-entities)))
- (nnweb-decode-entities))
+ (mm-url-remove-markup)
+ (mm-url-decode-entities-nbsp)
(goto-char (point-min))
(delete-blank-lines)
(goto-char (point-max))
(if (not (search-forward "</table>" nil t))
(webmail-error "article@5"))
(narrow-to-region p (match-end 0))
- (nnweb-remove-markup)
- (let ((w3-html-entities (cons '(nbsp . 32) w3-html-entities)))
- (nnweb-decode-entities))
+ (mm-url-remove-markup)
+ (mm-url-decode-entities-nbsp)
(goto-char (point-min))
(delete-blank-lines)
(setq ct (mail-fetch-field "content-type")
(widen)
(save-excursion
(set-buffer (generate-new-buffer " *webmail-att*"))
- (nnweb-insert (concat webmail-aux attachment))
+ (mm-url-insert (concat webmail-aux attachment))
(push (current-buffer) webmail-buffer-list)
(setq bufname (buffer-name)))
(insert "<#part")
(goto-char (point-min))
(while (re-search-forward "<br>" nil t)
(replace-match "\n"))
- (nnweb-remove-markup)
- (let ((w3-html-entities (cons '(nbsp . 32) w3-html-entities)))
- (nnweb-decode-entities))
+ (mm-url-remove-markup)
+ (mm-url-decode-entities-nbsp)
nil)
(t
(insert "<#part type=\"text/html\" disposition=inline>")
(goto-char (point-min))
(while (search-forward "<b>" nil t)
(replace-match "\n"))
- (nnweb-remove-markup)
- (let ((w3-html-entities (cons '(nbsp . 32) w3-html-entities)))
- (nnweb-decode-entities))
+ (mm-url-remove-markup)
+ (mm-url-decode-entities-nbsp)
(goto-char (point-min))
(delete-blank-lines)
(goto-char (point-min))
(let (bufname);; Attachment
(save-excursion
(set-buffer (generate-new-buffer " *webmail-att*"))
- (nnweb-insert (concat (car webmail-open-url) attachment))
+ (mm-url-insert (concat (car webmail-open-url) attachment))
(push (current-buffer) webmail-buffer-list)
(setq bufname (buffer-name)))
(insert "<#part type=" type)
(goto-char (point-min))
(while (search-forward "<b>" nil t)
(replace-match "\n"))
- (nnweb-remove-markup)
- (let ((w3-html-entities (cons '(nbsp . 32) w3-html-entities)))
- (nnweb-decode-entities))
+ (mm-url-remove-markup)
+ (mm-url-decode-entities-nbsp)
(goto-char (point-min))
(delete-blank-lines)
(goto-char (point-min))
(let (bufname);; Attachment
(save-excursion
(set-buffer (generate-new-buffer " *webmail-att*"))
- (nnweb-insert (concat (car webmail-open-url) attachment))
+ (mm-url-insert (concat (car webmail-open-url) attachment))
(push (current-buffer) webmail-buffer-list)
(setq bufname (buffer-name)))
(insert "<#part type=" type)
(let ((url (match-string 1)))
(setq base (match-string 2))
(erase-buffer)
- (nnweb-insert url)))
+ (mm-url-insert url)))
(goto-char (point-min))
(when (re-search-forward
"(\\([0-9]+\\) Message.?-[^>]*\\([0-9]+\\) New"
(match-beginning 0)
(point-max)))
(goto-char (point-min))
- (nnweb-remove-markup)
- (let ((w3-html-entities (cons '(nbsp . 32) w3-html-entities)))
- (nnweb-decode-entities))
+ (mm-url-remove-markup)
+ (mm-url-decode-entities-nbsp)
(goto-char (point-max))))
((looking-at "[\t\040\r\n]*<TABLE")
(save-restriction
(delete-region (point-min) (point-max))
(save-excursion
(set-buffer (generate-new-buffer " *webmail-att*"))
- (nnweb-insert url)
+ (mm-url-insert url)
(push (current-buffer) webmail-buffer-list)
(setq bufname (buffer-name)))
(insert "<#part type=\"" type "\"")
(narrow-to-region (point-min) (point))
(while (search-forward "\r\n" nil t)
(replace-match "\n"))
- (nnweb-remove-markup)
- (let ((w3-html-entities (cons '(nbsp . 32) w3-html-entities)))
- (nnweb-decode-entities))
+ (mm-url-remove-markup)
+ (mm-url-decode-entities-nbsp)
(goto-char (point-min))
(while (re-search-forward "\n\n+" nil t)
(replace-match "\n"))
--- /dev/null
+@echo off\r
+\r
+rem Modified once more by Frank Schmitt (ich@Frank-Schmitt.net)\r
+rem Modified by ShengHuo Zhu (zsh@cs.rochester.edu)\r
+rem Originally from make.bat by David Charlap (shamino@writeme.com)\r
+\r
+rem Clear PWD so emacs doesn't get confused\r
+set GNUS_PWD_SAVE=%PWD%\r
+set PWD=\r
+\r
+if "%1" == "" goto usage\r
+\r
+set emacs=xemacs.exe\r
+if "%2" == "" set copy="false"\r
+if "%2" == "copy" set copy=true\r
+if "%2" == "/copy" set copy=true\r
+\r
+cd lisp\r
+call %1\%emacs% -batch -q -no-site-file -l ./dgnushack.el -f dgnushack-compile\r
+if not %copy%==true goto info\r
+attrib -r %1\..\..\xemacs-packages\lisp\gnus\*.*\r
+copy *.el? %1\..\..\xemacs-packages\lisp\gnus\r
+\r
+:info\r
+set EMACSINFO=call %1\%emacs% -no-site-file -no-init-file -batch -q -l infohack.el -f batch-makeinfo\r
+cd ..\texi\r
+%EMACSINFO% message.texi\r
+%EMACSINFO% emacs-mime.texi\r
+%EMACSINFO% gnus.texi\r
+if not %copy%==true goto done\r
+copy gnus %1\..\..\xemacs-packages\info\r
+copy gnus-?? %1\..\..\xemacs-packages\info\r
+copy message %1\..\..\xemacs-packages\info\r
+copy emacs-mime %1\..\..\xemacs-packages\info\r
+\r
+:etc\r
+cd ..\etc\r
+copy gnus-tut.txt %1\..\..\xemacs-packages\etc\r
+\r
+:done\r
+cd ..\r
+goto end\r
+\r
+:usage\r
+echo Usage: make-x.bat :xemacs-dir: [/copy]\r
+echo.\r
+echo where: :xemacs-dir: is the directory you installed xemacs in \r
+echo (the directory where xemacs.exe is situated)\r
+echo eg. C:\Programme\XEmacs\XEmacs-21.4.3\i586-pc-win32\r
+echo /copy indicates that the compiled files should be copied to your\r
+echo emacs lisp, info, and etc directories\r
+echo.\r
+echo Note: If you have Emacs/w3 you should set the environment variable \r
+echo W3DIR to the directory where w3 is installed eg.\r
+echo set W3DIR=C:\Progra~1\XEmacs\xemacs-packages\lisp\w3\r
+\r
+rem Restore PWD so whoever called this batch file doesn't get confused\r
+set PWD=%GNUS_PWD_SAVE%\r
+set GNUS_PWD_SAVE=\r
+:end\r
\r
cd lisp\r
call %1\bin\%emacs% -batch -q -no-site-file -l ./dgnushack.el -f dgnushack-compile\r
-if not "%2" == "copy" goto info\r
+if not "%2" == "/copy" goto info\r
attrib -r %1\lisp\gnus\*\r
copy *.el* %1\lisp\gnus\r
\r
:info\r
-set EMACSINFOHACK="(while (re-search-forward \"@\\(end \\)?ifnottex\" nil t) (replace-match \"\"))"\r
+set EMACSINFO=call %1\bin\%emacs% -no-site-file -no-init-file -batch -q -l infohack.el -f batch-makeinfo\r
cd ..\texi\r
-call %1\bin\%emacs% -batch -q -no-site-file message.texi -eval %EMACSINFOHACK% -f texinfo-every-node-update -f texinfo-format-buffer -f save-buffer\r
-call %1\bin\%emacs% -batch -q -no-site-file emacs-mime.texi -eval %EMACSINFOHACK% -f texinfo-every-node-update -f texinfo-format-buffer -f save-buffer\r
-call %1\bin\%emacs% -batch -q -no-site-file gnus.texi -eval %EMACSINFOHACK% -eval "(setq max-lisp-eval-depth 600)" -f texinfo-every-node-update -f texinfo-format-buffer -f save-buffer\r
-if not "%2" == "copy" goto done\r
+%EMACSINFO% message.texi\r
+%EMACSINFO% emacs-mime.texi\r
+%EMACSINFO% gnus.texi\r
+if not "%2" == "/copy" goto done\r
copy gnus %1\info\r
copy gnus-?? %1\info\r
copy message %1\info\r
goto end\r
\r
:usage\r
-echo Usage: make :emacs-dir: [copy]\r
+echo Usage: make :emacs-dir: [/copy]\r
echo.\r
echo where: :emacs-dir: is the directory you installed emacs in\r
echo eg. d:\emacs\20.4\r
-echo copy indicates that the compiled files should be copied to your\r
+echo /copy indicates that the compiled files should be copied to your\r
echo emacs lisp, info, and etc directories\r
echo.\r
echo Note: If you have Emacs/w3 you should set the environment variable \r
gnus
gnus-[0-9]*
message
+sieve
gnustmp.texi
*.dvi
+*.dvi-x
+*.pdf-x
*.log
-etc
-herds
-misc
-picons
*.aux
-screen
-smilies
-xface
+*.latexi
gnus.ps
+gnus.pdf
+gnus.out
gnusmail.texi
pspackage.tar.gz
+gnus.tmplatexi
+gnus.gind
+gnus.cind
+gnus.ilg
+gnus.kind
+gnus.cidx
+gnus.gidx
+gnus.kidx
+gnus.toc
+gnus.idx
+gnus.tmplatexi1
+picons.tex
+xface.tex
+smiley.tex
+gnusconfig.tex
+old
+2002-01-01 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus.texi (Choosing Commands): Addition.
+
+2001-12-31 Rui Zhu <sprache@iname.com>
+
+ * emacs-mime.texi (Customization): Typo fix.
+
+2001-12-31 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus.texi (Article Display): Addition.
+
+ * emacs-mime.texi (Interface Functions): Addition.
+
+ * gnus.texi (Using MIME): Addition.
+
+2001-12-30 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus.texi (X-Face): Made into own node.
+ (Article Display): New.
+
+ * emacs-mime.texi (Interface Functions): Addition.
+
+ * message.texi (Message Headers): Addition.
+
+2001-12-29 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * emacs-mime.texi (Customization): Added example.
+
+ * gnus.texi (Selecting a Group): Addition.
+ (Tree Display): Addition.
+
+2001-12-26 Florian Weimer <fw@deneb.enyo.de>
+
+ * gnus.texi (Using GPG): Remove obsolete reference to gpg-2comp.
+
+2001-12-26 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (Summary Buffer Lines): Add xrefs. Suggested by
+ Arcady Genkin <agenkin-dated-1010249095.131f22@thpoon.com>.
+
+2001-12-26 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * gnus.texi (NNTP): Add a note for `nntp-prepare-post-hook'.
+
+2001-12-18 Josh Huber <huber@alum.wpi.edu>
+
+ * ChangeLog, gnus.texi, emacs-mime.texi: (oops) removed
+ buffer-file-coding-system
+
+2001-12-18 00:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * ChangeLog, gnus.texi, emacs-mime.texi: Local Variables `coding'
+ MUST be added!
+
+2001-12-17 Josh Huber <huber@alum.wpi.edu>
+
+ * ChangeLog: changed coding to buffer-file-coding-system
+ * emacs-mime.texi: changed -*- magic cookie -*- to Local Variables
+ * gnus.texi: same
+ * gnus-ref.tex: same
+ * refcard.tex: same
+
+2001-12-16 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (Saving Articles): Add muttprint.
+ (Article Commands): Mention muttprint.
+
+2001-12-15 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (Virtual Groups): Fix. From Raymond Scholz
+ <ray-2001@zonix.de>.
+
+2001-12-15 08:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi, emacs-mime.texi: Fix the header.
+
+2001-12-12 Didier Verna <didier@lrde.epita.fr>
+
+ * gnus.texi (Misc Group Stuff): advertise `gnus-group-news'.
+ * gnus.texi (Summary Mail Commands): advertise
+ `gnus-summary-news-other-window'.
+
+2001-12-10 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus.texi (Advanced Scoring Examples): Clarify that the
+ examples are rules, not complete score files.
+
+2001-12-09 Nevin Kapur <nevin@jhu.edu>
+
+ * gnus.texi (Expiring Mail): Add.
+
+2001-12-05 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus.texi (Splitting in IMAP): Typo. From Colin Marquardt
+ <c.marquardt@alcatel.de>.
+
+2001-12-03 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * infohack.el (infohack): To process write-protected files safely,
+ make this buffer be writable after `find-file'.
+ From TSUCHIYA Masatoshi <tsuchiya@namazu.org>
+
+2001-12-03 08:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * Makefile.in: Dependence.
+
+ * emacs-mime.texi: Add coding header.
+
+2001-12-01 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (Group Line Specification, Summary Buffer Lines):
+ Cross reference Positioning Point.
+
+2001-11-25 09:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi (Limiting): Addition.
+
+2001-11-19 Simon Josefsson <jas@extundo.com>
+
+ * message.texi (Header Commands, Insertion): Use C-c C-f C-i for
+ Importance: instead of C-c C-u. Move to Header Commands from
+ Insertion. Suggested by Per Abrahamsen <abraham@dina.kvl.dk>.
+
+2001-11-17 Simon Josefsson <jas@extundo.com>
+
+ * message.texi (Insertion): Use C-c C-u for Importance: instead of
+ C-c C-p (used by SC).
+
+2001-11-15 Simon Josefsson <jas@extundo.com>
+
+ * message.texi (Insertion): Add C-c C-p,
+ message-insert-importance-{low,high}.
+ (Various Commands): Fix typo.
+ (Insertion Variables): New section, all variables moved from
+ Commands->Insertion into this node, Variables->Insertion
+ Variables.
+
+2001-11-15 14:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi (Various Summary Stuff): Add gnus-newsgroup-variables.
+
+2001-11-15 11:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.texi (Security): @uref not @url.
+
+2001-11-15 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * sieve.texi (Standards): Changed @samp to @uref.
+
+ * message.texi (Security): Changed @code to @uref.
+
+ * gnus-faq.texi: Changed a lot of @file to @uref.
+
+ * emacs-mime.texi (Standards): Changed @samp to @uref.
+
+2001-11-13 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (Article Washing): Add `W s'.
+
+2001-11-12 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (Security, Using GPG):
+ * message.texi (Security):
+ * emacs-mime.texi (MML Definition): Add PGP.
+
+2001-11-09 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * message.texi (Movement): message-beginning-of-line.
+
+2001-11-07 Simon Josefsson <jas@extundo.com>
+
+ * sieve.texi (Examples): Add.
+ (Top): Add.
+
+ * gnus.texi (Saving Articles): Add gnus-summary-write-to-file.
+
+2001-11-07 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (Misc Group Stuff): Add cross reference to Composing
+ Messages. Suggested by "Golubev I. N." <gin@mo.msk.ru>.
+
+2001-11-04 09:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi: Use C-M- instead of M-C-.
+ * message.texi (Insertion): Ditto.
+ * sieve.texi (Managing Sieve): Ditto.
+ Suggested by Eli Zaretskii <eliz@is.elta.co.il>.
+
+2001-11-02 Simon Josefsson <jas@extundo.com>
+
+ * dir (File): Add Sieve.
+
+ * gnus.texi (Sieve Commands): Add crossposting.
+
+2001-11-01 23:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * texi2latex.el (latexi-translate): Typo.
+ (latexi-translate-file): Nine in a herd is enough.
+
+2001-11-01 Simon Josefsson <jas@extundo.com>
+
+ * sieve.texi (Installation): Workaround texi2latex bug (replacing
+ inside verbatim needs a \end{verbatim} earlier in the file).
+
+ * texi2latex.el (latexi-translate): Add sieve.
+
+2001-11-01 12:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi (Article Washing): Add a note.
+
+2001-11-01 Simon Josefsson <jas@extundo.com>
+
+ * Makefile.in: Add sieve.
+
+ * gnus.texi (Misc Group Stuff):
+ (Group Parameters): Add Sieve Commands.
+ (top-level): Include Sieve manual after Emacs MIME.
+
+2001-10-31 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (Group Parameters): Add integer `display'.
+ (IMAP): Fix.
+
+2001-10-31 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * gnus.texi (NNTP): Added documentation for
+ `nntp-prepare-post-hook'.
+
+2001-10-29 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (Customizing Articles): Sort list. Remove
+ duplicate. Suggested by Henrik Holm <henrik@tele.ntnu.no>.
+
+2001-10-27 Simon Josefsson <jas@extundo.com>
+
+ * message.texi (Insertion): Fix message-yank*-prefix.
+
+2001-10-25 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (Mail Source Specifiers): More info on SSL, kerberos etc.
+ (IMAP): Ditto. Suggested by Martin Blais <blais@discreet.com>.
+
+2001-10-23 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * gnus.texi (Posting Server): Use `native' instead of `nil' for
+ posting to native server.
+
+2001-10-22 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * dir (File): Add standard explanation header.
+
+2001-10-21 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus.texi (Mail Source Specifiers): Explain more explicitly what
+ happens for the `directory' entries. Say that mail from foo.spool
+ goes in the group foo.
+
+2001-10-19 Simon Josefsson <jas@extundo.com>
+
+ * Makefile.in (clean): rm gnus.out.
+ (distclean): rm gnusconfig.tex (moved from "clean").
+
+ * gnus.texi (Using MIME): s/mime/MIME/ for PDF version.
+
+2001-10-19 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus.texi (Finding the News): Disrecommend nnspool for Leafnode
+ users.
+
+2001-10-17 21:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi (Archived Messages): Add new line after @item.
+ From: Jesper Harder <harder@ifa.au.dk>
+
+2001-10-17 21:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi (Formatting Basics): Extended format specs.
+
+2001-10-17 Per Abrahamsen <abraham@dina.kvl.dk>
+
+ * gnus.texi (Summary Buffer Lines): Documment %( and %).
+
+2001-09-04 21:43:05 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus.texi (Topic Sorting): Addition.
+
+2001-10-13 19:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * refcard.tex, gnusref.tex: Merge with the version
+ from Felix Natter <f.natter@ndh.net>
+
+2001-10-13 12:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * refcard.tex: Set version to Oort.
+
+ * gnusref.tex: New key bindings in Oort Gnus.
+
+2001-10-12 18:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * Makefile.in (.dvi.ps): Use TEXPICTS.
+ (.latexi.dvi-x): Remove gnus.toc as well.
+
+ * gnuslogo-refcard.eps: Remove BeginProcSet.
+
+2001-10-12 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (Misc Group Stuff): Add UTF-8.
+ (Misc Article): Document wash status characters. Suggested by
+ david.goldberg6@verizon.net (David S. Goldberg).
+
+2001-10-10 08:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnusref.tex, refcard.tex: Use epsfig.
+
+ * gnuslogo-refcard.eps: Rename from gnuslog.refcard, and set a
+ suitable bounding box.
+
+ * Makefile.in (.dvi.ps): New rule.
+ (refcard.pdf): Use gnuslogo-refcard.eps.
+
+2001-10-09 22:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi: Add href and bookmarks for pdf version.
+
+2001-10-06 08:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * Makefile.in (uninstall): Add uninstall.
+
+2001-10-05 Simon Josefsson <jas@extundo.com>
+
+ * Makefile.in (clean): Add gnusconfig.tex. Suggested by Henrik
+ Enberg <henrik@enberg.org>.
+
+2001-10-04 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (Mail Source Customization): Add.
+
+2001-10-04 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * Makefile.in (dvi): Don't depend on tmps.
+
+2001-10-03 08:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * emacs-mime.texi (mailcap): rvplayer -> wavplayer. Thanks to
+ Martin Kretzschmar <Martin.Kretzschmar@inf.tu-dresden.de>.
+
+2001-09-29 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (Foreign Groups): Fix. Add "mailman".
+ (Document Groups): Ditto.
+
+2001-09-28 07:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * Makefile.in (.texi): Remove $@ first.
+
+ * infohack.el (infohack-remove-unsupported): Remove @iflatex lines.
+ (infohack): Specify a coding-system to save info files.
+ From Katsumi Yamaoka <yamaoka@jpl.org>
+
+2001-09-28 00:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnusconfig.tex.in: Use cmss if pfu is not found.
+
+2001-09-27 18:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * Makefile.in: Illustrated manual.
+ * gnus.texi: Put message.texi and emacs-mime.texi in the
+ illustrated manual.
+ * texi2latex.el: Ditto.
+
+2001-09-27 13:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi: Remove the extra white-space.
+
+2001-09-27 10:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnusconfig.tex.in: New.
+ * gnus.texi: Use it.
+ * pagestyle.sty: Don't set verbatim font.
+ * postamble.tex: Set in ...
+ * bembo.sty: Removed.
+ * Makefile.in (gnusconfig.tex): Check gnusconfig.tex.in.
+ (LATEX): Use configure.
+
+2001-09-26 00:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi (Limiting): Addition.
+
+2001-09-25 23:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi (Pterodactyl Gnus): Put @item in one line.
+
+2001-09-24 19:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi: eps path fix.
+ * postamble.tex: Ditto.
+ * texi2latex.el: Ditto.
+
+ * Makefile.in: Move some to ps/Makefile.in.
+
+2001-09-24 Simon Josefsson <jas@extundo.com>
+
+ * etc/*, herds/*, misc/*, picons/*, screen/*, smilies/*, xface/*:
+ New files, from pspackage.tar.gz.
+
+ * Makefile.in (distclean): Make veryclean.
+
+ * gnus.texi (Summary Mail Commands): Fix.
+ (Summary Post Commands): Fix.
+ (The Manual): Fix.
+
+2001-09-23 02:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi: Use "back end".
+
+2001-09-23 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (Top): Move IMAP up from "Other Sources" to "Select
+ Methods".
+ (Charsets): Update default value.
+ (Finding the Parent): Add nnimap.
+ (Security): Add.
+ (Mailing List): Add.
+ (Archived Messages): Comment out XEmacs 19 stuff.
+ (Using GPG): Add reference to message manual.
+ (Direct Functions): Mention OpenSSL as well as SSLeay.
+ (Mail Source Specifiers): Add recent IMAP :stream and
+ :authentication.
+ (Agent Commands): Fix.
+ (GroupLens): Add URL and note about this being historical.
+ (Wide Characters): Update default value.
+ (Picon Requirements): Remove old XEmacs 19 stuff.
+
+2001-09-22 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (Other Marks): Add Recent.
+
+2001-09-14 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (Mail Folders): Add.
+
+2001-09-11 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (Delayed Articles): Fix. Suggested by Paul Jarc
+ <prj@po.cwru.edu>.
+
+2001-09-08 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (MIME Commands): Add gnus-buttonized-mime-types.
+
+2001-09-08 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus.texi (Topic Commands): Make this the first subsection of
+ `Group Topics'. Rearrange keys to mention the most important keys
+ first and to have subsections. Add some more explanation for
+ C-k/C-y.
+ (Group Buffer): Add comment from Alex Schroeder as todo item.
+
+2001-09-06 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus.texi (Fancy Mail Splitting): Mention `delete' near the
+ explanation of `junk'.
+
+2001-09-04 Katsumi Yamaoka <yamaoka@jpl.org>
+
+ * gnus.texi (Optional Backend Functions): The default function to
+ make a date format is `message-make-date', which should produce a
+ time zone.
+
+2001-09-04 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus.texi (Optional Backend Functions): More detail about the
+ DATE arg for nnchoke-request-newgroups. Reported by Paul Jarc.
+
+2001-09-01 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus.texi (Hooking New Backends Into Gnus): Say where to put the
+ call for gnus-declare-backend. Add an index entry for
+ gnus-declare-backend. Suggested by Paul Jarc.
+
+2001-08-29 Simon Josefsson <jas@extundo.com>
+ From Anders Jackson <jackson@hig.se>
+
+ * gnus.texi (Group Parameters): Fix.
+
+2001-08-27 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (Archiving Mail): Add.
+
+2001-08-25 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (Mail Spool): Add marks.
+ (MH Spool): Doesn't use marks file.
+ (Mail Folders): Add marks.
+
+2001-08-25 Simon Josefsson <jas@extundo.com>
+ From Henrik Enberg <henrik@enberg.org>
+
+ * gnus.texi (Group Parameters): Fix.
+
+2001-08-24 16:03:31 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus.texi (Group Parameters): Fix.
+
+2001-08-24 Simon Josefsson <jas@extundo.com>
+
+ * Makefile.in (latexps): Make tmps.
+
+2001-08-24 Simon Josefsson <jas@extundo.com>
+ From Jesper Harder <harder@ifa.au.dk>
+
+ * Makefile.in (latexps): Escape {.
+
+ * splitindex: Ditto.
+
+2001-08-23 19:22:59 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus.texi (Group Parameters): Fix.
+ (Group Parameters): Addition.
+ (Limiting): Addition.
+
+2001-08-21 23:55:48 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus.texi (Score Variables): Fix.
+
+2001-08-20 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus.texi (Delayed Articles): New section. Documents
+ gnus-delay.el.
+ (Fancy Mail Splitting): Say that nnmail-cache-accepted-message-ids
+ must be non-nil for splitting with parents to work.
+
+2001-08-19 17:31:15 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus.texi (Other Marks): Addition.
+ (Positioning Point): New.
+ (Tabulation): New.
+
+2001-08-19 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus.texi (Getting Started Reading Mail): Use (nnml "") rather
+ than (nnml "private") as the example server specification. This
+ way, the example group names a few paragraphs further down are
+ correct, and I expect that most people are going to use the empty
+ string as name, anyway. Please holler if that is wrong.
+
+2001-08-18 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (Optional Backend Functions): Remove `set'
+ request-set-mark action.
+
+2001-08-18 00:40:10 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus.texi (Wide Characters): New section.
+
+2001-08-17 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi: Replace 20,20 with 23,23 for
+ gnus-summary-line-format.
+
+2001-08-17 14:24:14 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus.texi (Group Parameters): Document regexp substitution.
+ (Group Parameters): Addition.
+
+2001-08-11 23:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ From Nevin Kapur <nevin@jhu.edu>
+
+ * gnus.texi (September Gnus): Typo.
+
+2001-08-12 Simon Josefsson <jas@extundo.com>
+ Suggested by Kai.Grossjohann@CS.Uni-Dortmund.DE
+
+ * gnus.texi (Other Marks): Add recent.
+ (Optional Backend Functions): Add forward and recent.
+
+2001-08-12 Kai Grossjohann <grossjoh@ls6.informatik.uni-dortmund.de>
+
+ * gnus.texi (Window Layout): Renamed from `Windows
+ Configuration'. After all, we're not talking about Microsoft.
+ Suggested by Barry Fishman.
+
+2001-08-11 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus.texi (Summary Mail Commands): Remove duplicate explanation
+ of `S W'. Reported by Norbert Koch.
+
+2001-08-09 15:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ From Benjamin Rutt <brutt@bloomington.in.us>
+
+ * gnus.texi (Troubleshooting): Addition.
+
+2001-08-09 Simon Josefsson <jas@extundo.com>
+ From Benjamin Rutt <brutt@bloomington.in.us>
+
+ * gnus.texi (Mail Backend Variables): Fix.
+
+2001-08-04 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus.texi (Summary Buffer Lines): Mention `gnus-goto-colon'.
+
+2001-08-03 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus.texi (Backend Interface): Explain about article numbers.
+ Suggested by Paul Jarc.
+
+2001-08-02 22:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * emacs-mime.texi (Non-MIME): Addition.
+
+ * gnus.texi (Group Parameters): Addition.
+ (Mailing List): Addition.
+
+2001-08-01 Simon Josefsson <jas@extundo.com>
+
+ * texi2latex.el (latexi-translate-file): Don't use point-at-bol.
+ (latexi-translate-file): Translate some more things, including
+ some hardcoded things that cause problems for LaTeX. From Jesper
+ Harder <harder@ifa.au.dk>.
+
+2001-07-31 Simon Josefsson <jas@extundo.com>
+
+ * bembo.sty: New file.
+
+ * texi2latex.el (latexi-translate-file): Support @noindent.
+
+ * gnus-faq.texi (Reading News FAQ): Fix (@email -> @samp).
+
+2001-07-28 09:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ From Janne Rinta-Manty <rintaman@cs.helsinki.fi>
+
+ * gnus.texi (Read Articles): Typo.
+
+2001-07-25 22:22:22 Raymond Scholz <rscholz@zonix.de>
+
+ * gnus.texi (Fancy Mail Splitting): New variable
+ nnmail-split-fancy-with-parent-ignore-groups
+
+2001-07-24 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus.texi (Duplicates): Make split method regexp more specific,
+ in case other `Gnus-Warning' headers are added in the future.
+ Suggested by Karl Kleinpaste.
+
+2001-07-23 22:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ From Karl Kleinpaste <karl@charcoal.com>
+
+ * gnus.texi (Summary Buffer Lines): Add %B.
+
+2001-07-20 11:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ From Jesper Harder <harder@myrealbox.com>
+
+ * message.texi (Insertion): Addition.
+
+2001-07-19 22:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi (Charsets): Addition.
+
+2001-07-17 22:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi (Searching for Articles): Raw articles.
+
+2001-07-16 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * message.texi (Insertion): Refer to gnus-cite-attribution-suffix.
+
+2001-07-13 12:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi (RSS): Add.
+ From Christoph Conrad <cc@cli.de>.
+
+2001-07-13 08:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi (Incorporating Old Mail): Add index.
+
+2001-07-13 00:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi (Group Parameters): Add.
+
+2001-07-04 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (IMAP): Add.
+
+2001-07-04 Didier Verna <didier@lrde.epita.fr>
+
+ * gnus.texi (Example Methods): use the new nntp-open-connection
+ methods in the examples.
+ * gnus.texi (NNTP): update for the new nntp-open-connection methods.
+ * gnus.texi (Direct Functions): new node.
+ * gnus.texi (Indirect Functions): new node.
+ * gnus.texi (Common Variables): new node.
+
+2001-06-27 Simon Josefsson <jas@extundo.com>
+ From Ralph Schleicher <rs@nunatak.allgaeu.org>
+
+ * gnus.texi (MIME Commands): Add.
+
+2001-06-24 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus.texi (Summary Score Commands): Say that some commands
+ create ADAPT files.
+
+2001-06-23 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus.texi (Duplicates): Contents of Gnus-Warning header have
+ changed. Reported by Peter J Acklam.
+
+2001-06-19 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (IMAP): Fix `imtest' discussion.
+
+ * gnus-faq.texi (Frequently Asked Questions): Fix URL.
+
+2001-06-17 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus.texi (Group Line Specification): Explain why %t is only an
+ estimate.
+
+2001-06-16 Simon Josefsson <jas@extundo.com>
+
+ * gnus.texi (IMAP): Add.
+
+2001-06-13 15:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi (Article Washing): Add.
+
+2001-06-11 09:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi: behaviour -> behavior. Suggested by Eli Zaretskii
+ <eliz@is.elta.co.il>.
+
+2001-06-09 20:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi: Apply "overfull hbox" patch from Eli Zaretskii
+ <eliz@is.elta.co.il>.
+
+2001-06-07 16:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi (RSS): Add.
+
+2001-05-31 13:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi (Setting Marks): Add.
+
+2001-05-27 Simon Josefsson <simon@josefsson.org>
+
+ * message.texi (Insertion): Add message-yank-cited-prefix.
+
+2001-05-22 Simon Josefsson <simon@josefsson.org>
+ From Jesper Harder <harder@ifa.au.dk>
+
+ * gnus.texi (Article Washing): Add.
+
+2001-05-16 Simon Josefsson <simon@josefsson.org>
+ From Jesper Harder <harder@ifa.au.dk>
+
+ * texi2latex.el (latexi-translate-file): Also exchange ref.
+
+ * gnus.texi: Add \gnusref and \gnusuref.
+
+2001-05-16 Simon Josefsson <simon@josefsson.org>
+ From Raymond Scholz <ray-2001@zonix.de>
+
+ * gnus.texi (Using MIME): Add and fix.
+
+2001-05-05 Florian Weimer <fw@deneb.enyo.de>
+
+ * gnus.texi (IMAP): Remove double paragraph (suggest by Norbert
+ Koch), fix NNTP reference.
+
+2001-05-04 08:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ Suggested by Dan Christensen <jdc@uwo.ca>
+
+ * gnus.texi (Mail Group Commands): Add pxref.
+ (Group Maintenance): Ditto.
+ (Topic Commands): Ditto.
+ (Expiring Mail): Typo.
+
+2001-05-04 08:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ From Raymond Scholz <ray-2001@zonix.de>
+
+ * gnus.texi (Summary Buffer Lines): Mention the meaning of a
+ colon.
+
+2001-05-03 07:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+ From Sriram Karra <karra@cs.utah.edu>.
+
+ * gnus.texi: Add default value.
+
+2001-05-03 06:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi (Using GPG): Use example environment.
+
+2001-05-02 17:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus.texi (Expunging mailboxes): Typo.
+
2001-04-15 19:38:54 Lars Magne Ingebrigtsen <larsi@gnus.org>
* gnus.texi (Mail and Post): Fix.
2001-03-11 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* message.texi (Message Headers): Update doc for
- `message-generate-headers-first'.
+ `message-generate-headers-first'.
2001-03-14 15:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
From Nevin Kapur <nevin@jhu.edu>
* gnus.texi (Posting Server): Fix, due to change of default value
of `gnus-post-method' to `current'.
-
+
2001-02-23 08:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
* gnus.texi: Remove double words. From Gerd Moellmann.
* infohack.el (batch-makeinfo): New.
-
+
* Makefile.in (EMACSINFO): Use it.
2001-02-17 13:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
2001-02-06 19:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
* gnus.texi (Using GPG): Key binding.
-
+
* message.texi (Security): Ditto.
2001-02-06 18:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
* message.texi (message-ignored-news-headers): Add "X-Draft-From:".
(message-ignored-mail-headers): Ditto.
-
+
2001-01-21 Raymond Scholz <ray-2001@zonix.de>
* message.texi: Rename X-Mailer and X-Newsreader to User-Agent.
2001-01-10 15:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
- * gnus.texi (Article Washing): makeinfo 1.69 doesn't grok `anchor'.
+ * gnus.texi (Article Washing): makeinfo 1.69 doesn't grok `anchor'.
2001-01-07 18:18:53 Lars Magne Ingebrigtsen <larsi@gnus.org>
2001-01-03 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* gnus.texi (Article Washing): Mention `C-u g' as a sort of
- anti-washing.
+ anti-washing.
2001-01-01 11:40:34 Lars Magne Ingebrigtsen <larsi@gnus.org>
* gnus.texi (Archived Messages): Explain what happens when group
names mentioned in `gnus-message-archive-group' contain a select
- method.
+ method.
2000-10-28 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
2000-07-03 00:24:55 Lars Magne Ingebrigtsen <larsi@gnus.org>
- * gnus.texi (Splitting Mail): Mention gnus-summary-respool-trace.
+ * gnus.texi (Splitting Mail): Mention gnus-summary-respool-trace.
(Searching for Articles): Fix.
(Newest Features): Fix.
2000-04-26 02:30:06 Shenghuo ZHU <zsh@cs.rochester.edu>
- * gnus.texi (Posting Styles): Addition.
+ * gnus.texi (Posting Styles): Addition.
2000-04-24 17:09:17 Felix Natter <f.natter@ndh.net>
1998-08-27 07:29:17 Lars Magne Ingebrigtsen <larsi@gnus.org>
* gnus.texi (Mail Folders): Addition.
-
+
;; Local Variables:
;; coding: iso-2022-7bit
;; End:
EMACSCOMP=$(EMACS) -batch -q -no-site-file
EMACSINFO=$(EMACSCOMP) -l $(srcdir)/infohack.el -f batch-makeinfo
PDFLATEX=pdflatex
-LATEX=latex
+LATEX=@LATEX@
DVIPS=dvips
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
SHELL = /bin/sh
PAPERTYPE=a4
-INFO_DEPS=gnus message emacs-mime
+INFO_DEPS=gnus message emacs-mime sieve
all: $(INFO_DEPS)
most: texi2latex.elc latex latexps
-.SUFFIXES: .texi .dvi .ps .pdf
+.SUFFIXES: .texi .dvi .ps .pdf .latexi .dvi-x .pdf-x
.texi:
if test "x$(MAKEINFO)" != "xno" ; then \
$(MAKEINFO) -I $(srcdir) -o $* $<; \
else \
+ rm -f $@; \
$(EMACSINFO) $<; \
fi
-dvi: gnus.dvi message.dvi refcard.dvi emacs-mime.dvi
+dvi: gnus.dvi message.dvi refcard.dvi emacs-mime.dvi sieve.dvi
-pdf: gnus.pdf message.pdf refcard.pdf emacs-mime.pdf
+pdf: gnus.pdf message.pdf refcard.pdf emacs-mime.pdf sieve.pdf
.texi.dvi :
sed -e '/@iflatex/,/@end iflatex/d' $< > gnustmp.texi
$(TEXI2DVI) -I $(srcdir) gnustmp.texi
cp gnustmp.dvi $*.dvi
- rm gnustmp.*
+ rm -f gnustmp.*
+
+.dvi.ps :
+ TEXPICTS=$(srcdir) $(DVIPS) -t $(PAPERTYPE) -f $< > $@
.texi.pdf :
sed -e '/@iflatex/,/@end iflatex/d' $< > gnustmp.texi
$(TEXI2PDF) -I $(srcdir) gnustmp.texi
cp gnustmp.pdf $*.pdf
- rm gnustmp.*
+ rm -f gnustmp.*
-refcard.dvi: refcard.tex gnuslogo.refcard gnusref.tex
+refcard.dvi: refcard.tex gnuslogo-refcard.eps gnusref.tex
TEXINPUTS=$(srcdir):$$TEXINPUTS $(LATEX) refcard.tex
-
-refcard.pdf: refcard.tex gnuslogo.refcard gnusref.tex
- epstopdf $(srcdir)/gnuslogo.refcard --outfile=gnuslogo.refcard.pdf
+refcard.pdf: refcard.tex gnuslogo-refcard.eps gnusref.tex
+ epstopdf $(srcdir)/gnuslogo-refcard.eps --outfile=gnuslogo-refcard.pdf
TEXINPUTS=$(srcdir):$$TEXINPUTS $(PDFLATEX) refcard.tex
clean:
*.pdf *.tp *.toc *.pg gnus.latexi *.aux *.[cgk]idx \
gnus.ilg gnus.ind gnus.[cgk]ind gnus.idx \
gnustmp.texi *.tmplatexi gnus.tmplatexi1 texput.log *.orig *.rej \
- gnus.latexi*~* tmp/*.ps xface.tex picons.tex smiley.tex *.latexi
+ gnus.latexi*~* xface.tex picons.tex smiley.tex *.latexi *.dvi-x \
+ *.pdf-x gnus.out
makeinfo:
makeinfo -o gnus gnus.texi
texi2latex.elc: texi2latex.el
srcdir=$(srcdir)/../lisp $(EMACSCOMP) -l $(srcdir)/../lisp/dgnushack.el --eval '(byte-compile-file "$(srcdir)/texi2latex.el")'
-latex gnus.latexi gnus-faq.latexi: $(srcdir)/gnus.texi $(srcdir)/gnus-faq.texi texi2latex.elc
+latex: gnus.latexi gnus-faq.latexi message.latexi emacs-mime.latexi sieve.latexi
+
+gnus.latexi gnus-faq.latexi message.latexi emacs-mime.latexi sieve.latexi: $(srcdir)/gnus.texi $(srcdir)/gnus-faq.texi $(srcdir)/message.texi $(srcdir)/emacs-mime.texi $(srcdir)/sieve.texi texi2latex.elc
srcdir=$(srcdir) $(EMACSCOMP) -l ./texi2latex.elc -f latexi-translate
-latexps: gnus.latexi
- make texi2latex.elc
- rm -f gnus.aux
- egrep -v "label.*Index|chapter.*Index" gnus.latexi > gnus.tmplatexi1
- TEXINPUTS=$(srcdir):$$TEXINPUTS $(LATEX) gnus.tmplatexi1
- ./splitindex
+.latexi.dvi-x:
+ make gnusconfig.tex
+ make tmps
+ rm -f gnus.aux gnus.toc
+ cp $< gnus.tmplatexi
+ TEXINPUTS=$(srcdir):$$TEXINPUTS $(LATEX) gnus.tmplatexi
+ $(srcdir)/splitindex
+ makeindex -o gnus.kind gnus.kidx
+ makeindex -o gnus.cind gnus.cidx
+ makeindex -o gnus.gind gnus.gidx
+ sed 's/\\char 5E\\relax {}/\\symbol{"5E}/' < gnus.kind > gnus.tmpkind
+ mv gnus.tmpkind gnus.kind
+ egrep -v "end\{document\}" $< > gnus.tmplatexi
+ cat $(srcdir)/postamble.tex >> gnus.tmplatexi
+ TEXINPUTS=$(srcdir):$$TEXINPUTS $(LATEX) gnus.tmplatexi
+ TEXINPUTS=$(srcdir):$$TEXINPUTS $(LATEX) gnus.tmplatexi
+ mv gnus.dvi $@
+
+.latexi.pdf-x:
+ make gnusconfig.tex
+ make tmps
+ cd ps; make pdf
+ rm -f gnus.aux gnus.toc
+ cp $< gnus.tmplatexi
+ TEXINPUTS=$(srcdir):$$TEXINPUTS $(PDFLATEX) gnus.tmplatexi
+ $(srcdir)/splitindex
makeindex -o gnus.kind gnus.kidx
makeindex -o gnus.cind gnus.cidx
makeindex -o gnus.gind gnus.gidx
sed 's/\\char 5E\\relax {}/\\symbol{"5E}/' < gnus.kind > gnus.tmpkind
mv gnus.tmpkind gnus.kind
- egrep -v "end{document}" gnus.tmplatexi1 > gnus.tmplatexi
- cat postamble.tex >> gnus.tmplatexi
- $(LATEX) gnus.tmplatexi
- $(LATEX) gnus.tmplatexi
- $(DVIPS) -t $(PAPERTYPE) -f gnus.dvi > gnus.ps
-
-pss:
- make latex
- make latexps
-
-psout:
- make latex
- make latexboth
- make out
-
-latexboth:
- rm -f gnus-manual-a4.ps.gz gnus-manual-standard.ps.gz
- make latexps
- mv gnus.ps gnus-manual-a4.ps
- gzip gnus-manual-a4.ps
- sed 's/,a4paper/,letterpaper/' gnus.latexi > gnus-standard.latexi
- mv gnus-standard.latexi gnus.latexi
- make latexps PAPERTYPE=letter
- mv gnus.ps gnus-manual-standard.ps
- gzip gnus-manual-standard.ps
+ egrep -v "end\{document\}" $< > gnus.tmplatexi
+ cat $(srcdir)/postamble.tex >> gnus.tmplatexi
+ TEXINPUTS=$(srcdir):$$TEXINPUTS $(PDFLATEX) gnus.tmplatexi
+ TEXINPUTS=$(srcdir):$$TEXINPUTS $(PDFLATEX) gnus.tmplatexi
+ mv gnus.pdf $@
+
+latexps: latex gnus.dvi-x
+ TEXPICTS=$(srcdir) $(DVIPS) -t a4 -f $< > gnus.ps
+
+latexpdf: latex gnus.pdf-x
+ mv gnus.pdf-x gnus.pdf
+
+gnus-manual-a4.latexi: gnus.latexi
+ cp $< $@
+
+gnus-manual-standard.latexi: gnus.latexi
+ sed 's/,a4paper/,letterpaper/' $< > $@
+
+gnus-manual-a4.ps.gz: gnus-manual-a4.dvi-x
+ TEXPICTS=$(srcdir) $(DVIPS) -t a4 -f $< | gzip -c > $@
+
+gnus-manual-standard.ps.gz: gnus-manual-standard.dvi-x
+ TEXPICTS=$(srcdir) $(DVIPS) -t letter -f $< | gzip -c > $@
+
+pdfs: gnus-manual-a4.pdf-x gnus-manual-standard.pdf-x
+ mv gnus-manual-a4.pdf-x gnus-manual-a4.pdf
+ mv gnus-manual-standard.pdf-x gnus-manual-standard.pdf
+
+pss: latexps
+
+complete: pss
+
+psout: latexboth out
+
+latexboth: gnus-manual-a4.ps.gz gnus-manual-standard.ps.gz
out:
cp gnus-manual-standard.ps.gz \
gnus-manual-a4.ps.gz \
/hom/larsi/www_docs/www.gnus.org/documents
-veryclean:
- make clean
+veryclean: clean
rm -f gnus.dvi gnus.ps texi2latex.elc
+ rm -f gnus-manual-a4.* gnus-manual-standard.*
-distclean:
- make clean
+distclean: veryclean
rm -f *.orig *.rej *.elc *~ gnus-[0-9] gnus-[0-9][0-9] Makefile
rm -f message-[0-9]
rm -f $(INFO_DEPS)
+ rm -f gnusconfig.tex
install: $(INFO_DEPS)
$(SHELL) $(top_srcdir)/mkinstalldirs $(infodir)
done; \
else : ; fi
-tmps:
- if [ ! -e tmp ]; then mkdir tmp; fi
- make screens
- make herdss
- make etcs
- make piconss
- make xfaces
- make smiley
- make miscs
-
-herdss:
- cd herds ; for i in new-herd-[0-9]*.gif; do echo $$i; giftopnm $$i | pnmcrop -white | pnmmargin -white 9 | pnmscale 2 | pnmconvol convol5.pnm | ppmtopgm | pnmdepth 255 | pnmtops -width 100 -height 100 -noturn > ../tmp/`basename $$i .gif`.ps; done
- cd herds ; giftopnm new-herd-section.gif | pnmscale 4 | pnmconvol convol11.pnm | ppmtopgm | pnmdepth 255 | pnmtops -noturn -width 100 -height 100 > ../tmp/new-herd-section.ps
-
-
-screens:
- cd screen ; for i in *.gif; do echo $$i; giftopnm $$i | pnmmargin -black 1 | ppmtopgm | pnmtops -width 100 -height 100 -noturn > ../tmp/`basename $$i .gif`.ps; done
-
-miscs:
- giftopnm misc/larsi.gif | ppmtopgm | pnmtops -noturn > tmp/larsi.ps
- tifftopnm misc/eseptember.tif | pnmscale 4 | ppmtopgm | pnmtops -noturn -width 100 -height 100 > tmp/september.ps
- tifftopnm misc/fseptember.tif | pnmscale 2 | ppmtopgm | pnmtops -noturn -width 100 -height 100 > tmp/fseptember.ps
- tifftopnm misc/fred.tif | pnmscale 2 | ppmtopgm | pnmtops -noturn -width 100 -height 100 > tmp/fred.ps
- tifftopnm misc/ered.tif | pnmscale 2 | ppmtopgm | pnmtops -noturn -width 100 -height 100 > tmp/red.ps
-
-etcs:
- cd etc; for i in gnus-*.xpm; do echo $$i; xpmtoppm $$i | ppmtopgm | pnmdepth 255 | pnmtops -noturn > ../tmp/`basename $$i .xpm`.ps; done
-
-piconss:
- cd picons; for i in *.xbm; do echo $$i; xbmtopbm $$i | pnmtops -noturn > ../tmp/picons-`basename $$i .xbm`.ps; done
- cd picons; for i in *.gif; do echo $$i; giftopnm $$i | ppmtopgm | pnmtops -noturn > ../tmp/picons-`basename $$i .gif`.ps; done
- for i in tmp/picons-*.ps; do echo "\\gnuspicon{$$i}"; done > picons.tex
-
-xfaces:
- cd xface; for i in *.gif; do echo $$i; giftopnm $$i | ppmtopgm | pnmtops -noturn > ../tmp/xface-`basename $$i .gif`.ps; done
- for i in tmp/xface-*.ps; do \
+uninstall:
+ @list='$(INFO_DEPS)'; \
+ for file in $$list; do \
+ for ifile in `echo $$file $$file-[0-9] $$file-[0-9][0-9]`; do \
+ rm -f $(infodir)/$$ifile; \
+ done; \
+ done
+ @if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then \
+ list='$(INFO_DEPS)'; \
+ for file in $$list; do \
+ echo " install-info --delete --info-dir=$(infodir) $(infodir)/$$file";\
+ install-info --delete --info-dir=$(infodir) $(infodir)/$$file || :;\
+ done; \
+ else : ; fi
+
+tmps:
+ cd ps; make all
+ for j in ps/picons-*.ps; do \
+ i=ps/`basename $$j .ps`; \
+ echo "\\gnuspicon{$$i}"; done > picons.tex
+ for j in ps/xface-*.ps; do \
+ i=ps/`basename $$j .ps`; \
if [ -n "$$a" ]; then a=""; echo "{$$i}"; else \
a="h"; echo -n "\\gnusxface{$$i}"; fi done > xface.tex; \
if [ -n "$$a" ]; then echo "{$$i}" >> xface.tex; fi
-
-smiley:
- cd smilies; tifftopnm BigFace.tif | ppmtopgm | pnmtops > ../tmp/BigFace.ps
- cd smilies; for i in *.xpm; do echo $$i; sed "s/none/#FFFFFF/" $$i | xpmtoppm | ppmtopgm | pnmdepth 255 | pnmtops > ../tmp/smiley-`basename $$i .xpm`.ps; done
- for i in tmp/smiley-*.ps; do \
+ for j in ps/smiley-*.ps; do \
+ i=ps/`basename $$j .ps`; \
if [ -n "$$a" ]; then a=""; echo "{$$i}"; else \
a="h"; echo -n "\\gnussmiley{$$i}"; fi done > smiley.tex; \
if [ -n "$$a" ]; then echo "{$$i}" >> smiley.tex; fi
-
pspackage:
+ cd ps; make clean
tar czvf pspackage.tar.gz gnus-faq.texi gnus.texi herds misc pagestyle.sty picons pixidx.sty postamble.tex ps screen smilies splitindex texi2latex.el xface Makefile README etc
-complete:
- make texi2latex.elc
- make tmps
- make pss
-
Makefile: $(srcdir)/Makefile.in ../config.status
cd .. \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+gnusconfig.tex: $(srcdir)/gnusconfig.tex.in ../config.status
+ cd .. \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
# 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:
-*- Text -*-
The Gnus-related top node.
+
+This is the file .../info/dir, which contains the topmost node of the
+Info hierarchy. The first time you invoke Info you start off
+looking at that node, which is (dir)Top.
\1f
File: dir Node: Top This is the Gnus Info tree
+ This (the Directory node) gives a menu of major topics.
+ Typing "d" returns here, "q" exits, "?" lists all INFO commands, "h"
+ gives a primer for first-timers, "mEmacs<Return>" visits the Emacs topic,
+ etc.
+ In Emacs, you can click mouse button 2 on a menu item or cross reference
+ to select it.
+ --- PLEASE ADD DOCUMENTATION TO THIS TREE. (See INFO topic first.) ---
* Menu:
* Gnus: (gnus). The news reader Gnus.
* Message: (message). The Message sending thingamabob.
* Emacs MIME: (emacs-mime). Libraries for handling MIME.
+* Sieve: (sieve). Managing Sieve scripts in Emacs.
-\input texinfo @c -*-texinfo-*-
+\input texinfo
@setfilename emacs-mime
@settitle Emacs MIME Manual
This file documents the Emacs MIME interface functionality.
-Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.1 or
@item mail-header-narrow-to-field
@findex mail-header-narrow-to-field
-Narrow the buffer to the header under point.
+Narrow the buffer to the header under point. Understands continuation
+headers.
+
+@item mail-header-fold-field
+@findex mail-header-fold-field
+Fold the header under point.
+
+@item mail-header-unfold-field
+@findex mail-header-unfold-field
+Unfold the header under point.
+
+@item mail-header-field-value
+@findex mail-header-field-value
+Return the value of the field under point.
@item mail-encode-encoded-word-region
@findex mail-encode-encoded-word-region
@end example
This says that all image files should be displayed with @code{gimp}, and
-that realaudio files should be played by @code{rvplayer}.
+that WAVE audio files should be played by @code{wavplayer}.
The @code{mailcap} library parses this file, and provides functions for
matching types.
@menu
* Dissection:: Analyzing a @sc{mime} message.
+* Non-MIME:: Analyzing a non-@sc{mime} message.
* Handles:: Handle manipulations.
* Display:: Displaying handles.
* Customization:: Variables that affect display.
descend the message, following the structure, and return a tree of
@sc{mime} handles that describes the structure of the message.
+@node Non-MIME
+@section Non-MIME
+
+Gnus also understands some non-MIME attachments, such as postscript,
+uuencode, binhex, shar, forward, gnatsweb, pgp. Each of these features
+can be disabled by add an item into @code{mm-uu-configure-list}.
+For example,
+
+@lisp
+(require 'mm-uu)
+(add-to-list 'mm-uu-configure-list '(pgp-signed . disabled))
+@end lisp
+
+@table @code
+@item postscript
+@findex postscript
+Postscript file.
+
+@item uu
+@findex uu
+Uuencoded file.
+
+@item binhex
+@findex binhex
+Binhex encoded file.
+
+@item shar
+@findex shar
+Shar archive file.
+
+@item forward
+@findex forward
+Non-@sc{mime} forwarded message.
+
+@item gnatsweb
+@findex gnatsweb
+Gnatsweb attachment.
+
+@item pgp-signed
+@findex pgp-signed
+PGP signed clear text.
+
+@item pgp-encrypted
+@findex pgp-encrypted
+PGP encrypted clear text.
+
+@item pgp-key
+@findex pgp-key
+PGP public keys.
+
+@item emacs-sources
+@findex emacs-sources
+Emacs source code. This item works only in the groups matching
+@code{mm-uu-emacs-sources-regexp}.
+
+@end table
@node Handles
@section Handles
However, users may prefer other types instead, and this list says what
types are most unwanted. If, for instance, @samp{text/html} parts are
very unwanted, and @samp{text/richtech} parts are somewhat unwanted,
-then the value of this variable should be set to:
+you could say something like:
@lisp
-("text/html" "text/richtext")
+(setq mm-discouraged-alternatives
+ '("text/html" "text/richtext")
+ mm-automatic-display
+ (remove "text/html" mm-automatic-display))
@end lisp
@item mm-inline-large-images-p
makes the library display all inline images as inline, regardless of
their size.
-@item mm-inline-override-p
+@item mm-inline-override-type
@code{mm-inlined-types} may include regular expressions, for example to
specify that all @samp{text/.*} parts be displayed inline. If a user
prefers to have a type that matches such a regular expression be treated
The size (in octets) of the part (@code{Content-Disposition}).
@item sign
-What technology to sign this MML part with (@code{smime} or
-@code{pgpmime})
+What technology to sign this MML part with (@code{smime}, @code{pgp}
+or @code{pgpmime})
@item encrypt
-What technology to encrypt this MML part with (@code{smime} or
-@code{pgpmime})
+What technology to encrypt this MML part with (@code{smime},
+@code{pgp} or @code{pgpmime})
@end table
The Emacs @sc{mime} library implements handling of various elements
according to a (somewhat) large number of RFCs, drafts and standards
documents. This chapter lists the relevant ones. They can all be
-fetched from @samp{http://quimby.gnus.org/notes/}.
+fetched from @uref{http://quimby.gnus.org/notes/}.
@table @dfn
@item RFC822
@contents
@bye
+\f
+@c Local Variables:
+@c mode: texinfo
+@c coding: iso-8859-1
@c End:
--- /dev/null
+/* XPM */
+static char * picon-bar_xpm[] = {
+"6 48 2 1",
+" c white s background",
+". c black",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. ",
+" .. "};
--- /dev/null
+/* XPM */
+static char * icon-catchup_xpm[] = {
+"32 32 4 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #999999999999",
+"o c #FFFFFFFFFFFF",
+" ",
+" ",
+" ",
+" ",
+" .... ",
+" .XXXX. .... ",
+" .XXXX. .XXXX.",
+" .XXX. .XXXX.",
+" .........XX. .XXX.",
+".ooooooooo.. .........XX. ",
+".o....ooooo...... .ooooooooo.. ",
+"X. .ooooooooo.X..o....ooooo. ",
+"X. .oooo........X. .ooooo. ",
+". .oooo. .X. .ooooo. ",
+" .oooo. .. .oooo.o. ",
+" .oooo. .oooo.o. ",
+" ...... .ooooo.oo..",
+" .ooooo. ...... ..X.",
+" .ooooo. .ooooo. ..",
+" .o..ooo. ..oooo. ",
+".ooo..ooo.XXXXXXXXX.o..ooo.XXXXX",
+"ooo.XX.oo.XXX......ooo..ooo.XXXX",
+"oo.XXX.oo.XXX..oooooo.XX.oo.XXXX",
+"..XXXX.oo.XXX..ooooo.XXX.oo.XXXX",
+"XXXXXXX.oo.XX.......XXX .oo.XXXX",
+"XXXXXXX.....X..XXXXXXXXXX.oo.XXX",
+"XXXXXXXXXXXXX.XXXXXXXXXXX.....XX",
+"XXXXXXXXXXXXXXXXXXXXXXXXX......X",
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"};
--- /dev/null
+/* XPM */
+static char * icon-catchup_xpm[] = {
+"32 32 4 1",
+" c #BFBFBFBFBFBF",
+". c #000000000000",
+"X c #999999999999",
+"o c #FFFFFFFFFFFF",
+" ",
+" ",
+" ",
+" ",
+" .... ",
+" .XXXX. .... ",
+" .XXXX. .XXXX.",
+" .XXX. .XXXX.",
+" .........XX. .XXX.",
+".ooooooooo.. .........XX. ",
+".o....ooooo...... .ooooooooo.. ",
+"X. .ooooooooo.X..o....ooooo. ",
+"X. .oooo........X. .ooooo. ",
+". .oooo. .X. .ooooo. ",
+" .oooo. .. .oooo.o. ",
+" .oooo. .oooo.o. ",
+" ...... .ooooo.oo..",
+" .ooooo. ...... ..X.",
+" .ooooo. .ooooo. ..",
+" .o..ooo. ..oooo. ",
+".ooo..ooo.XXXXXXXXX.o..ooo.XXXXX",
+"ooo.XX.oo.XXX......ooo..ooo.XXXX",
+"oo.XXX.oo.XXX..oooooo.XX.oo.XXXX",
+"..XXXX.oo.XXX..ooooo.XXX.oo.XXXX",
+"XXXXXXX.oo.XX.......XXX .oo.XXXX",
+"XXXXXXX.....X..XXXXXXXXXX.oo.XXX",
+"XXXXXXXXXXXXX.XXXXXXXXXXX.....XX",
+"XXXXXXXXXXXXXXXXXXXXXXXXX......X",
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"};
--- /dev/null
+/* XPM */
+static char * icon-describe-group_xpm[] = {
+"32 32 4 1",
+" c #000000000000",
+". c #999999999999 s backgroundToolBarColor",
+"X c #FFFFFFFFFFFF",
+"o c #BFBFBFBFBFBF",
+" ... ... ... ... ... ... ... ...",
+"................................",
+"................................",
+".......................XXXXX....",
+" ... ... ... ... ... XXX XXXXX..",
+"....................XXXXXXXXXXX.",
+"...................XXXXXXXXXXXXX",
+"..................XXXXXXXXXXXXXX",
+" ... ... ... ... XXX XXX XXX XXX",
+"................XXXXXXXXXXXXXXXX",
+"................XXXXXXXXXXXXXXXX",
+"................XXXXXXXXXXXXXXXX",
+" ... ... ... ... XXX XXX XXX XXX",
+"................XXXXXXXXXXXXXXXX",
+"................XXXXXXXXXXXXXXXX",
+"................XXXXXXXXXXXXXXXX",
+" ... ... ... ... XXX XXX XXX XXX",
+".................XXXXXXXXXXXXXXX",
+".................XXXXXXXXXXXXXXX",
+"....... .......XXXXXXXXXXXXXX",
+" ... . oooo ... ..X XXX XXX XXX",
+"..... o...oo .......XXXXXXXXXXX.",
+".... .o....o. .......XXXXXXXXX..",
+".... o . ... .........XXXXX....",
+" ... o .. . .. ... ... ... ...",
+"... o . . ..................",
+".. X . . . ...................",
+". o . . ....................",
+" o . ... ... ... ... ...",
+" o .........................",
+"o . ...o......................",
+" ..........................."};
--- /dev/null
+/* XPM */
+static char * icon-exit-gnus_xpm[] = {
+"32 32 4 1",
+" c #FFFFFFFFFFFF s backgroundToolBarColor",
+". c #000000000000",
+"X c #999999999999",
+"o c #BFBFBFBFBFBF",
+" . ",
+" .. .. ",
+" . .. ... ",
+" ... .. . . ",
+" . . ... . . .... ..... ",
+" . .. .... ..... .. . . .. ",
+" . . .. . ... .. . . ",
+" . ...... ",
+" .... ... ... ",
+" .... ......... ... ",
+" .. . . .X.. .. .... ",
+" . .X. .. . . ... ",
+" .X. . . .. . . ",
+" .X. .. .. . ",
+".. . . ..X.. .. .... . .. .. . ",
+"ooooooo.X.ooo..ooo..oo ooooooooo",
+"oooo oo.X.ooo.ooooo..oooooooo oo",
+"o oooo.X.ooooooo ooo.ooooooooooo",
+"oooooo.X.ooooooooooooooo ooooooo",
+"ooo oo.X.ooo ooooooooooooooooooo",
+"oooooo.X.oooooooooo oooooo ooo",
+"ooooo.X.ooooooooooooooo ooooooo",
+"o ooo.X.oooooo ooooooooooooooooo",
+"ooooo.X.oooo o ooooooooo ooooo",
+"ooooo.X.ooooooooooo oooo o ooo",
+"oo....X...ooooooo o oooooooooo",
+"o..XX...XX..ooo.o.oo.oo oooooooo",
+".XX.XX..X.XX...ooo.oo o oooooo",
+"X.XX.XXXXXXXXXX..oooo.o.oooooo o",
+".................o.o oo.oooo o ",
+"oooooo ooo.oo oo.o . ooooooooo",
+"oooo o oo o oooooooooooooooo"};
--- /dev/null
+/* XPM */
+static char * icon-get-new-news-this-group_xpm[] = {
+"32 32 4 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+"o c #999999999999",
+" ",
+" .......... ",
+" .XXXXXXXX. ",
+" .XXXXXXXX. ",
+" .XXXXXXXX. .... ",
+" .XXXXXXXX. .oooo. ",
+" .XXXXXXX.... .oooooo. ",
+" .XXXXXXX.. . .oooooo. ",
+" .XXXXXXXX...o. .oooooo. ",
+" .XXXXXXXX..ooo. .oooo. ",
+" .XXXXXXXX. .ooo. .oo. ",
+" .XXXXXXXX. .ooo.....o.... ",
+" .XXXXXXXX. .oooooooooooo. ",
+" .......... .oooooooooooo. ",
+" .oooooooooooo. ",
+" .oooooooo.oo. ",
+" .ooooooo.oo. ",
+" .ooooooo.oo. ",
+" .ooooooo.oo. ",
+" .ooooooo.oo. ",
+" .ooooooo.oo. ",
+" .ooooooo.oo. ",
+" ............ ",
+" .oooooo. . ",
+" .ooooooo.. . ",
+" .ooooooo. . ",
+" .oooo.oo... ",
+" .oooo.oooo. ",
+" .ooo. .ooo. ",
+" ..... ..... ",
+" .o. .o. ",
+" .o. .o. "};
--- /dev/null
+/* XPM */
+static char * icon-get-new-news_xpm[] = {
+"32 32 4 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+"o c #999999999999",
+" ",
+".......... ",
+".XXXXXXXX. ",
+".XXXXXXXX. ",
+".XXXXXXXX. .... ",
+".XXXXXXXX. .oooo. ",
+".XXXXXXX.... .oooooo. ",
+".XXXXXXX.. . .oooooo. ",
+".XXXXXXXX...o. .oooooo. ",
+".XXXXXXXX..ooo. .oooo. ",
+".XXXXXXXX. .ooo. .oo. ",
+".XXXXXXXX. .ooo.....o.... ",
+".XXXXXXXX. .oooooooooooo. ",
+".......... .oooooooooooo. ",
+" .oooooooooooo. ",
+" .ooooooooooo. ",
+" .o.......oo.....",
+" .o.XXXXX.oo.XXX.",
+" .o.XXXX.ooo.XXX.",
+" .o.XXXX.oo.XXXX.",
+" .o.XXX.ooo.XXXX.",
+" .o.XXX.oo.XXXXX.",
+" ...XX...o.XXXXX.",
+" .oo.X. .XXXXXX.",
+" .oo.XX.. .XXXXXX.",
+" .oo.... ........",
+" .oooo.o..o. ",
+" .oooo.oooo. ",
+" .ooo. .ooo. ",
+" ..... ..... ",
+" .o. .o. ",
+" .o. .o. "};
--- /dev/null
+/* XPM */
+static char * icon-killfile_xpm[] = {
+"32 32 3 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+" ",
+" ",
+" ",
+" ",
+" ................ ",
+" .XXXXXXXXXXXXXX.. ",
+" .XXXXXXXXXXXXXX.X. ",
+" .XXXXXXX...XXXX.XX. ",
+" .XXXXXX.....XXX..... ",
+" .XXXXX..X.X..XXXXXX. ",
+" .XXXXX.......XXXXXX. ",
+" .XXXXX...X...XXXXXX. ",
+" .XXXXXX.....XXXXXXX. ",
+" .XXXXXXX.X.XXXXXXXX. ",
+" .XXXXXXX.X.XXXXXXXX. ",
+" .XXXX.XX...X.XXXXXX. ",
+" .XXX..XXXXXX..XXXXX. ",
+" .XXXXX..XX..XXXXXXX. ",
+" .XXXXXXX..XXXXXXXXX. ",
+" .XXXXXXX..XXXXXXXXX. ",
+" .XXXXX..XX..XXXXXXX. ",
+" .XXX..XXXXXX..XXXXX. ",
+" .XXXX.XXXXXX.XXXXXX. ",
+" .XXXXXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXXXXX. ",
+" .................... ",
+" ",
+" ",
+" "};
--- /dev/null
+/* XPM */
+static char * icon-unsubscribe_xpm[] = {
+"32 32 3 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+" ",
+" ",
+" ",
+" ",
+" ................ ",
+" .XXXXXXXX.XXXXX.. ",
+" .XX.X.XXX.XXXXX.X. ",
+" .XXX.XXXX.XXXXX.XX. ",
+" .XX.X.XXX.XXXXX..... ",
+" .XXXXXXXX.XXXXXXXXX. ",
+" ..........XXXXXXXXX. ",
+" .XXXXXXXX.XXXXXXXXX. ",
+" .XX.X.XXX.XXXXXXXXX. ",
+" .XXX.XXXX.XXXXXXXXX. ",
+" .XX.X.XXX.XXXXXXXXX. ",
+" .XXXXXXXX.XXXXXXXXX. ",
+" ..........XXXXXXXXX. ",
+" .XXXXXXXX.XXXXXXXXX. ",
+" .XX.X.XXX.XXXXXXXXX. ",
+" .XXX.XXXX.XXXXXXXXX. ",
+" .XX.X.XXX.XXXXXXXXX. ",
+" .XXXXXXXX.XXXXXXXXX. ",
+" ..........XXXXXXXXX. ",
+" .XXXXXXXX.XXXXXXXXX. ",
+" .XXXXXXXX.XXXXXXXXX. ",
+" .XXXXXXXX.XXXXXXXXX. ",
+" .XXXXXXXX.XXXXXXXXX. ",
+" .XXXXXXXX.XXXXXXXXX. ",
+" .................... ",
+" ",
+" ",
+" "};
--- /dev/null
+/* XPM */
+static char * icon-subscribe_xpm[] = {
+"32 32 3 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+" ",
+" ",
+" ",
+" ",
+" ................ ",
+" .XXXXXXXX.XXXXX.. ",
+" .XXXXXX.X.XXXXX.X. ",
+" .XXXXX.XX.XXXXX.XX. ",
+" .XX.X.XXX.XXXXX..... ",
+" .XXX.XXXX.XXXXXXXXX. ",
+" ..........XXXXXXXXX. ",
+" .XXXXXXXX.XXXXXXXXX. ",
+" .XXXXXX.X.XXXXXXXXX. ",
+" .XXXXX.XX.XXXXXXXXX. ",
+" .XX.X.XXX.XXXXXXXXX. ",
+" .XXX.XXXX.XXXXXXXXX. ",
+" ..........XXXXXXXXX. ",
+" .XXXXXXXX.XXXXXXXXX. ",
+" .XXXXXX.X.XXXXXXXXX. ",
+" .XXXXX.XX.XXXXXXXXX. ",
+" .XX.X.XXX.XXXXXXXXX. ",
+" .XXX.XXXX.XXXXXXXXX. ",
+" ..........XXXXXXXXX. ",
+" .XXXXXXXX.XXXXXXXXX. ",
+" .XXXXXXXX.XXXXXXXXX. ",
+" .XXXXXXXX.XXXXXXXXX. ",
+" .XXXXXXXX.XXXXXXXXX. ",
+" .XXXXXXXX.XXXXXXXXX. ",
+" .................... ",
+" ",
+" ",
+" "};
--- /dev/null
+/* XPM */
+static char * icon-rot13_xpm[] = {
+"32 32 3 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+" ",
+" ",
+" ",
+" ",
+" ................ ",
+" .XXXXXXXXXXXXXX.. ",
+" .XX..XX...XXX...X. ",
+" .X.XX.X.XX.X.XX.XX. ",
+" .X.XX.X.X.XX.XX..... ",
+" .X....X.XX.X.XXXXXX. ",
+" .X.XX.X...XXX...XXX. ",
+" .XXXXXXXXXXXXXXXXXX. ",
+" .XX.XXXXX.XXXX.XXXX. ",
+" .XXXXXXXXXXXXXXXXXX. ",
+" .X..X.XX..XX...XXXX. ",
+" .X..X.X.XX.X.XX.XXX. ",
+" .X.X..X.XX.X...XXXX. ",
+" .X.X..X.XX.X.XXXXXX. ",
+" .X.XX.XX..XX.XXXXXX. ",
+" .XXXXXXXXXXXXXXXXXX. ",
+" .XXXX..XXXXXXXXXXXX. ",
+" .XXX....XXXXXXXXXXX. ",
+" .XX..XX.........XXX. ",
+" .XX..XX.........XXX. ",
+" .XXX....XXX.X.X.XXX. ",
+" .XXXX..XXXX.X.X.XXX. ",
+" .XXXXXXXXXXXX.XXXXX. ",
+" .XXXXXXXXXXXXXXXXXX. ",
+" .................... ",
+" ",
+" ",
+" "};
--- /dev/null
+/* XPM */
+static char * icon-cancel-post_xpm[] = {
+"32 32 4 1",
+" c #000000000000",
+". c #BFBFBFBFBFBF s backgroundToolBarColor",
+"X c #FFFFFFFFFFFF",
+"o c #999999999999",
+" ... ... ... ... ....... ... ...",
+"................................",
+"................................",
+"................................",
+" ... ... ... ... .... ... ...",
+"............... XX ............",
+"............. XXXX ...........",
+"........... XXXX X ...........",
+" ... .... XXXXX X ... ... ...",
+"........ XXXXXXX XXX ..........",
+"........ XXXXXX oXXXX ..........",
+"........o XXXXXXXoXXXX .........",
+" ... ...oo XXXXXXXX . ... ...",
+".........oo XXXXX oooo.........",
+"..........oo o..............",
+"..........ooooooo...............",
+" ... ... ... oo. ... ... ... ...",
+"................................",
+"................................",
+"................................",
+" ... ... ... ... ... ... ... ...",
+"................................",
+"................................",
+"................................",
+" ... ... ... ... ... ... ... ...",
+"................................",
+"................................",
+"................................",
+" ... ... ... ... ... ... ... ...",
+"................................",
+"................................",
+"................................"};
--- /dev/null
+/* XPM */
+static char * icon-catchup_xpm[] = {
+"32 32 4 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+"o c #999999999999",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ...... ",
+" .. .XXXX. ",
+" .X. .XXXX. ",
+" ..XX...XXXXX.... ",
+" ..XXXXX..XXXXX.XX... ",
+" ..XXXXX..XXXX.XXXX.. ",
+" .XXXX........XXXX. ",
+" ..XXX.XXXXX....... ",
+" ..XXX.XXXXX..XXX. ",
+" .X.XX.XXXXX.XXXX. ",
+" ...XX.XXXXX.XXXX. ",
+" ...X.XXXXX.X... ",
+" .X.........XX. ",
+" . .XX.XX.XX. ",
+"ooooooooo....XX.XX....oooooooooo",
+"oooooooooo. ....... .oooooooooo",
+"oooooooooo.X.XX.X .X.ooooooooooo",
+"oooooooooo. .X . . .ooooooooooo",
+"oooooooooo...........ooooooooooo",
+"oooooooooo...X..XX...ooooooooooo",
+"oooooooooo...X ..X...ooooooooooo",
+"oooooooooo..........oooooooooooo",
+"oooooooooooo.......ooooooooooooo",
+"oooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooo"};
--- /dev/null
+/* XPM */
+static char * icon-catchup2_xpm[] = {
+"32 32 2 1",
+" c #000000000000",
+". c #BFBFBFBFBFBF s backgroundToolBarColor",
+" ... ... ... ... ... ... ... ...",
+"................................",
+"................................",
+"................................",
+" ... ... ... ... ... ... ... ...",
+"................................",
+"................................",
+"................. .............",
+" ... ... ... ... . ... ... ...",
+"................ ..............",
+"............... ................",
+"................................",
+" ... ... ... ... ... ... ... ...",
+"................................",
+"................................",
+"............. .......... .....",
+" ... ... ... . ... ... . ...",
+"............ .......... ......",
+"........... ........... ........",
+"............ .......... .......",
+" ... ... ... . . ... ... ... ...",
+"............... ..... ",
+"................ ... ......",
+"........ ..... ... ...... .....",
+" ... .. .. . . . . .. . .",
+"....... .... .... ... .. . ... ",
+"...... ...... ... ..... ... ...",
+"...... .. .... ...... .. ..",
+" ... ... . ... .. .. ..",
+"........... .... . .... .",
+".......... ..... ..... .. .",
+".......... ..... ....... ... "};
--- /dev/null
+/* XPM */
+static char * icon-exit-summary_xpm[] = {
+"32 32 2 1",
+" c #000000000000",
+". c #BFBFBFBFBFBF s backgroundToolBarColor",
+" ... ... ... ... ... ... ... ...",
+"................................",
+"................................",
+"................................",
+" ... ...... ... ...",
+"........ ....... .......",
+"........ ........... .......",
+"........ .......... .......",
+" ... ... ... ....... ... ...",
+"................ ... .......",
+".................... .......",
+"........ .......... .......",
+" ... ... ... ....... ... ...",
+"........ ....... . .......",
+"........ ....... . .......",
+"........ ....... . .......",
+" ... ... ... ....... ... ...",
+"........ .......... .......",
+"........ ........... .......",
+"................ ... .......",
+" ... ....... ....... ... ...",
+"........ .......... .......",
+"........ ........ . . .......",
+"........ .... . . . . ........",
+" ... .. .. . . . . ... ...",
+"................................",
+"................................",
+"................................",
+" ... ... ... ... ... ... ... ...",
+"................................",
+"................................",
+"................................"};
--- /dev/null
+/* XPM */
+static char * icon-followup_xpm[] = {
+"32 32 3 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+" ",
+" . . . . . . . . ",
+" ",
+" ",
+" ... ",
+" . . . . ..XX. . . . ",
+" ..XXXX.. ",
+" ..XXXX..X. ",
+" ..XXXXX...X. ",
+" . . ..XXXXXXX..XXX. . . ",
+" ..XXXXXXXX.XXXXX. ",
+" .XXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXX. ",
+" . . .XXXXXXXXXXXXXXX. . . ",
+" .XXXX...XXXXXXX. ",
+" .X..XX.XXXXXXXX. ",
+" ..XXXX..XXXXXXX. ",
+" . ..XXXX..X.XXXXXXXX. . ",
+" ..XXXXX...X.XXXXXXXX. ",
+" ..XXXXXXX..XXX.XXXXXXXX. ",
+" .XXXXXXXX.XXXXX.XXXXXXXX. ",
+" ..XXXXXXXXXXXXXX.XXXXXXXXX. . ",
+" .XXXXXXXXXXXXXXX.XXXXXXX.. ",
+" .XXXXXXXXXXXXXXX.XXXX.. ",
+" .XXXXXXXXXXXXXXX.XX.. ",
+" . .XXXXXXXXXXXXXXX.. . . ",
+" .XXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXX. ",
+" . .XXXXXXXXXXXXXXX. . . ",
+" .XXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXX. "};
--- /dev/null
+/* XPM */
+static char * icon-followup-w-orig_xpm[] = {
+"32 32 3 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+" ",
+" . . . . . . . . ",
+" ",
+" ",
+" ",
+" . . . . . . . . ",
+" ",
+" .. ",
+" ... ",
+" . . . . .. . . . ",
+" . ",
+" ",
+" ",
+" . . . . . . . . ",
+" .. ",
+" ..XX. ",
+" ..XXXX. ",
+" . ..XXX...X. . . . ",
+" ..XXX..XX..X. ",
+" ..XXX..XXX...X. ",
+" .XX..XXXXX...XX. ",
+" . ...XXXXXX.XX.XX. . . . ",
+" .XXXXXXXXXXXX.XX. ",
+" .XXXXXXXXXXXXX.XX. ",
+" .XXXXXXXXXXXXXX.XX. ",
+" . .XXXXXXXXXXXXX.XX. . . ",
+" .XXXXXXXXXXXXXX.XX. ",
+" .XXXXXXXXXXXXX.XX. ",
+" .XXXXXXXXXXXXXX.XX. ",
+" . .XXXXXXXXXXXXX.XX. . . ",
+" .XXXXXXXXXXXXXX.XX. ",
+" .XXXXXXXXXXXXX.XX. "};
--- /dev/null
+/* XPM */
+static char * icon-mail-copy_xpm[] = {
+"32 32 3 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+" ",
+" ",
+" .......................... ",
+" ...XXXXXXXXXXXXXXXXXXX..X. ",
+" .XX..XXXXXXXXXXXXXXX..XXX. ",
+" .XXXX..XXXXXXXXXXX..XXXXX. ",
+" .XXXXXX..XXXXXXX..XXXXXXX. ",
+" .XXXXXXXX..XXX..XXXXXXXXX. ",
+" .XXXXXXXX.X...XX.XXXXXXXX. ",
+" .XXXXXX..XXXXXXXX..XXXXXX. ",
+" .XXXXX.XXXXXXXXXXXX.XXXXX. ",
+" .XX.......................... ",
+" .XX.X.XXXXXXXXXXXXXXXXXXX..X. ",
+" .X..XX..XXXXXXXXXXXXXXX..XXX. ",
+" ..X.XXXX..XXXXXXXXXXX..XXXXX. ",
+" ....XXXXXX..XXXXXXX..XXXXXXX. ",
+" .XXXXXXXX..XXX..XXXXXXXXX. ",
+" .XXXXXXXX.X...X.XXXXXXXXX. ",
+" .XXXXXXX.XXXXXXX..XXXXXXX. ",
+" .XXXXX..XXXXXXXXXX.XXXXXX. ",
+" .XXXX.XXXXXXXXXXXXX.XXXXX. ",
+" .XXX.XXXXXXXXXXXXXXX..XXX. ",
+" .X..XXXXXXXXXXXXXXXXXX.XX. ",
+" ..XXXXXXXXXXXXXXXXXXXXX... ",
+" .......................... ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" "};
--- /dev/null
+/* XPM */
+static char * icon-mail-delete_xpm[] = {
+"32 32 4 1",
+" c #BEBEBEBEBEBE s backgroundToolBarColor",
+"X c #000000000000",
+"o c #E7E7E7E7E7E7",
+"O c #FFFFFFFFFFFF",
+" ",
+" ",
+" ",
+" XXXXX ",
+" XX XX ",
+" XX XX XXX ",
+" X X XXooXX X ",
+" XX XXX XXooXX XX ",
+" XX XXXXX XXXXX XOXXX ",
+" XXXXX XXXXXX XOOXOOXX",
+" XOX XOOOXOOOX",
+" XXXXX XXXXXX XOOOXOOOO",
+" XX XXXXX XXXXXX XOOXOOOO",
+" XX XXX XXXXXXXOOOXOOOO",
+" X X XOOOOOOXOOOOO",
+" XX XX XOOOOOOOXOOOOO",
+" XX XX XOOOOOOOXXOOOOO",
+" XXXXX XOOOOOXXXOOOOOOO",
+" XOOOXXXOOOOOOOOOO",
+" XOXXXOOOOOOOOOOOOX",
+" XXXOOOOOOOOOOOOOOX ",
+" XXOOOOOOOOOOOOOX ",
+" XXOOOOOOOOOOOX ",
+" XOOOOOOOOOX ",
+" XXOOOOOOX ",
+" XXOOOX ",
+" XXOX ",
+" X ",
+" ",
+" ",
+" ",
+" "};
--- /dev/null
+/* XPM */
+static char * icon-mail-forward_xpm[] = {
+"32 32 3 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+" ",
+" ",
+" ... ",
+" . . ",
+" . . . ",
+" . ... ",
+" ... ...XX. ",
+" . . . .XX.XXX. ",
+" . . . .XX.XXXX.. ",
+" . . . .XXX.XXXXX.. ",
+" . . . .XXX.XXXXXXX. ",
+" .. . ..XXXX.XXXXXXXX. ",
+" . . .XXXXXX.XXXXXXXXX. ",
+" . .XXXXXX.XXXXXXXXXX. ",
+" .XXXXXXX............. ",
+" .XXXXXXX.XXXXXXXXXXX. ",
+" .XXXXXXX..XXXXXXXXX.. ",
+" ..XXXXX....XXXXXXXXX. ",
+" .XXX.....XXXXXXXXXXX. ",
+" ....XXXX.XXXXXXXXXX. ",
+" ..XXXXXXX.XXXXXXXXX. ",
+" .XXXXXXX.XXXXXXXXX. ",
+" .XXXXXX.XXXXXXX.. ",
+" ..XXXXX.XXXXXX. ",
+" ..XXXX.XXXXX. ",
+" .XXXX.XXXX. ",
+" .XXX.XXX. ",
+" .X.XX.. ",
+" ..X. ",
+" ... ",
+" ",
+" "};
--- /dev/null
+/* XPM */
+static char * icon-mail-get_xpm[] = {
+"32 32 3 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ... ... ",
+" . . . . ",
+" . . . . ",
+" . . . . .. ",
+" . .. .. .. ",
+" .XXXXXXX. .XXXXXXX. ",
+" .XXXXX. .XXXXX. ",
+" ..XXX.. ..XXX.. ",
+" ... ... ",
+" ",
+" .......................... ",
+" ...XXXXXXXXXXXXXXXXXXX..X. ",
+" .XX..XXXXXXXXXXXXXXX..XXX. ",
+" .XXXX..XXXXXXXXXXX..XXXXX. ",
+" .XXXXXX..XXXXXXX..XXXXXXX. ",
+" .XXXXXXXX..XXX..XXXXXXXXX. ",
+" .XXXXXXX.XX...X.XXXXXXXXX. ",
+" .XXXXX..XXXXXXXX..XXXXXXX. ",
+" .XXXX.XXXXXXXXXXXX.XXXXXX. ",
+" .XXX.XXXXXXXXXXXXXX.XXXXX. ",
+" .X..XXXXXXXXXXXXXXXX..XXX. ",
+" ..XXXXXXXXXXXXXXXXXXXX.XX. ",
+" .XXXXXXXXXXXXXXXXXXXXXX... ",
+" .......................... ",
+" ",
+" ",
+" "};
--- /dev/null
+/* XPM */
+static char * icon-mail-originate_xpm[] = {
+"32 32 3 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+" ",
+" ",
+" ............. ",
+" .XXXXXXXXXX.X. ",
+" .XXXXXXXXXX.XX. ",
+" .XXXXXXXXXX.... ",
+" ..................XXXXXXXX. ",
+" .X. X X X X X X .X..XXXXXX. ",
+" ..................XXXXXXXX. ",
+" .XXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXX. ",
+" .XX.......XXXX. ",
+" ..............XXXXXXXXXXXXX. ",
+" ...XXXXXXXXXX.XX..X..X.XXXX. ",
+" .XX..XXXXXXXX.XXXXXXXXXXXXX. ",
+" .XXXX..XXXXXX.XXXXXXXXXXXXX. ",
+" .XXXXXX..XXXX.XXXXXXXXXXXXX. ",
+" .XXXXXXXX..XX.XXXXXXXXXXXXX. ",
+" .XXXXXXX.XX...XXXXXXXXXXXXX. ",
+" .XXXXX..XXXXX.XXXXXXX..X.XX. ",
+" .XXXX.XXXXXXX.XXXXXXXXXXXXX. ",
+" .XXX.XXXXXXXX.XXXXXXXXXXXXX. ",
+" .X..XXXXXXXXX.XXXXXXXXXXXXX. ",
+" ..XXXXXXXXXXX............... ",
+" .XXXXXXXXXXXXXXXXXXXXXX... ",
+" .......................... ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" "};
--- /dev/null
+/* XPM */
+static char * icon-mail-reply_xpm[] = {
+"32 32 3 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+" ",
+" ... ",
+" .XXX.. ",
+" .XXXXXX.. ",
+" ... .XXXXXXXX. ",
+" ..XXX.XX.XXXXXX. ",
+" ..XXXX.XXX.XXXXX. ",
+" ..XXXXXX.XX.XXXXX. ",
+" ..XXXXXXX.XX.XXXXXX. ",
+" .XXXXXXXX.XXX.XXXXX... ",
+" ..XX..XX.XX.XXXXXXXX.XXX.. ",
+" ...XXXXXXX.XX.XXXXX.XX..X. ",
+" .XX..XXXX.XXX.XXXXX...XXX. ",
+" .XXXX..XX.XX.XXXXX..XXXXX. ",
+" .XXXXXX...XXXXXX..XXXXXXX. ",
+" .XXXXXXXX..XXX..XXXXXXXXX. ",
+" .XXXXXXX.XX...X.XXXXXXXXX. ",
+" .XXXXX..XXXXXXXX..XXXXXXX. ",
+" .XXXX.XXXXXXXXXXXX.XXXXXX. ",
+" .XXX.XXXXXXXXXXXXXX.XXXXX. ",
+" .X..XXXXXXXXXXXXXXXX..XXX. ",
+" ..XXXXXXXXXXXXXXXXXXXX.XX. ",
+" .XXXXXXXXXXXXXXXXXXXXXX... ",
+" .......................... ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" "};
--- /dev/null
+/* XPM */
+static char * icon-save-mail_xpm[] = {
+"32 32 6 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+"o c #999999999999",
+"O c #E5E5E5E5E5E5",
+"+ c #666666666666",
+" ",
+" ",
+" ",
+" ........................ ",
+" ...XXXXXXXXXXXXXXXXXX... ",
+" .XX..XXXXXXXXXXXXXX..XX. ",
+" .XXXX..XXXXXXXXXX..XXXX. ",
+" .XXXXXX..XXXXXX..XXXXXX. ",
+" .XXXXXXX...XX..XXXXXXXX. ",
+" .XXXXX..XXX..XX..XXXXXX. ",
+" .XXXX.XXXXXXXXXXX.XXXXX. ",
+" .XXX.XXXXXXXXXXXXX..XXX. ",
+" .X..XXXXXXXXXXXXXXXX..X. ",
+" ..................XXXXXXXXX.. ",
+" .oo.OOOOOOOOOO.oo.XXXXXXXXXX. ",
+" .oo.OOOOOOOOOO.oo............ ",
+" .oo.OOOOOOOOOO.oo. ",
+" .oo.OOOOOOOOOO.oo. ",
+" .oo.OOOOOOOOOO.oo. ",
+" .oo.OOOOOOOOOO.oo. ",
+" .oo.OOOOOOOOOO.oo. ",
+" .oo.OOOOOOOOOO.oo. ",
+" .oo............oo. ",
+" .oooooooooooooooo. ",
+" .oooooooooooooooo. ",
+" .oo............oo. ",
+" .oo.+++++++.OO.oo. ",
+" .oo.+++++++.OO.oo. ",
+" .oo.+++++++.OO.oo. ",
+" .o.+++++++.OO.oo. ",
+" ................ ",
+" "};
--- /dev/null
+/* XPM */
+static char * icon-next-unread_xpm[] = {
+"32 32 4 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+"o c #999999999999",
+" ",
+" . . . . . . . . ",
+" ",
+" ",
+" ... ",
+" . . . . ..XX. . . . ",
+" ..XXXX.. ",
+" ..XXXX..X. ",
+" ..XXXXX...X. ",
+" . . ..XXXXXXX..XXX. . . ",
+" ..XXXXXXXX.XXXXX. ",
+" .XXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXX. ",
+" . . .XXXXXXXXXXXXXXX. . . ",
+" .XXXX...XXXXXXX. ",
+" .X..XX.XXXXXXXX. ",
+" ..XXXX..XXXXXXX. ",
+" . ..XXXX..X.XXXXXXXX. . ",
+" ..XXXXX...X.XXXXXXXX. ",
+" ..XXXXXXX..XXX.XXXXXXXX. ",
+" .XXXXXXXX.XXXXX.XXXXXXXX. ",
+" ..XXXXXXXXXXXXXX.XXXXXXXXX. . ",
+" .XXXXXXXXXXXXXXX.XXXXXXX.. ",
+" .XX.....XXXXXXX.....X.. ",
+" .X.ooooo.XXXXX.oooo.. ",
+" . .oXooooo.XXX.oXooooo.. . ",
+" .ooooooo.X.X.ooooooo. ",
+" .ooooooo..X..ooooooo. ",
+" ..oooooo.XXX.ooooooo. ",
+" . ..oooo.XXXXX.oooo.. . . ",
+" .....XXXXXXX..... ",
+" .XXXXXXXXXXXXXXX. "};
--- /dev/null
+/* XPM */
+static char * icon-post_xpm[] = {
+"32 32 3 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+" ",
+" . . . . . . . . ",
+" ",
+" ",
+" ... ",
+" . . . . ..XX. . . . ",
+" ..XXXX.. ",
+" ..XXXX..X. ",
+" ..XXXXX...X. ",
+" . . ..XXXXXXX..XXX. . . ",
+" ..XXXXXXXX.XXXXX. ",
+" .XXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXX. ",
+" . . .XXXXXXXXXXXXXXX. . . ",
+" .XXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXX. ",
+" . . .XXXXXXXXXXXXXXX. . ",
+" .XXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXX. ",
+" . . . .XXXXXXXXXXXXXXX. . ",
+" .XXXXXXXXXXXXXX.. ",
+" .XXXXXXXXXX... ",
+" .XXXXXXXXX. ",
+" . . . .XXXXXX.. . . ",
+" .XXX... ",
+" .... ",
+" ",
+" . . . . . . . . ",
+" ",
+" "};
--- /dev/null
+/* XPM */
+static char * icon-prev-unread_xpm[] = {
+"32 32 4 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+"o c #999999999999",
+" ",
+" . . . . . . . . ",
+" ",
+" ",
+" ... ",
+" . . . . ..XX. . . . ",
+" ..XXXX.. ",
+" ..XXXX..X. ",
+" ..XXXXX...X. ",
+" . . ..XXXXXXX..XXX. . . ",
+" ..XXXXXXXX.XXXXX. ",
+" .XXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXX. ",
+" . . .XXXXXXXXXXXXXX. . . ",
+" .XXXX...XXXXXX..... ",
+" ...o..XX.XXXXX.oooo.. ",
+" .oo..XXXX..XXX.oXooooo. ",
+" . .o..XXXX..X.X.X.ooooooo.. ",
+" ..XXXXX...X..X..ooooooo. ",
+" ..XXXXXXX..XX.XXX.ooooooo. ",
+" .XXXXXXXX.XXXXX.XXX.oooo.. ",
+" ..XXXXXXXXXXXXXX.XXXX..... . ",
+" .XXXXXXXXXXXXXXX.XXXX. ",
+" .XXXXXXXXXXXXXX.XX.. ",
+" .XXXXXXXXXXXXXXX.. ",
+" . .XXXXXXXXXXXXXXX. . . ",
+" .XXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXX. ",
+" . .XXXXXXXXXXXXXXXX. . . ",
+" .XXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXX. "};
--- /dev/null
+/* XPM */
+static char * icon-follow-up_xpm[] = {
+"32 32 4 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+"o c #999999999999",
+" ",
+" ",
+" ",
+" ",
+" ",
+" . ",
+" .X.. ",
+" ... .XXXX. ",
+" ..XXX.XXXXXX.. ",
+" ..XXXX.XXXXXXXXX. ",
+" ..XXXXX.XXXXXXXXX.. ",
+" ..XXXXXXX.XXXXXXXX.... ",
+" ..XXXXXXXX.XXXXXXXXX.oXX.. ",
+" .X..X.X.X..XXXXXXXXX..o...o. ",
+" ..XXXXXXX.XXXXXXXXX..ooXXX.. ",
+" .X...XXXX.XXXXXXXX..ooX...X. ",
+" .XXXX.XX.XXXXXXXX..oX..XXXX. ",
+" .XXXXX..XXXXXXXX..oX.XXXXXX. ",
+" .XXXXXXX..XXXXX..X..XXXXXXX. ",
+"oo.XXXXXXXXX.XXX....XXXXXXXXX.oo",
+"oo.XXXXXXXXX...X...XXXXXXXXXX.oo",
+"oo.XXXXXXXX.XX...XX.XXXXXXXXX.oo",
+"oo.XXXXXXX.XXXXXXXXX.XXXXXXXX.oo",
+"oo.XXXXXX.XXXXXXXXXXX.XXXXXXX.oo",
+"oo.XXXX..XXXXXXXXXXXXX..XXXXX.oo",
+"oo.XXX.XXXXXXXXXXXXXXXXX.XXXX.oo",
+"oo.XX.XXXXXXXXXXXXXXXXXXX.XXX.oo",
+"oo...XXXXXXXXXXXXXXXXXXXXX....oo",
+"oo..XXXXXXXXXXXXXXXXXXXXXXXX..oo",
+"oo............................oo",
+"oooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooo"};
--- /dev/null
+/* XPM */
+static char * icon-follow-up-incl_xpm[] = {
+"32 32 4 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+"o c #999999999999",
+" ",
+" ",
+" ",
+" ",
+" ... ",
+" .X.X. ",
+" .XX.XX.. ",
+" .XXX.XXXX. ",
+" ..XXX.XXXXXX.. ",
+" ..X.XXX.XXXXXXX.. ",
+" ..XX.XXXX.XXXXX.... ",
+" ..XXX.XXXXX.X....XX... ",
+" ..XXX..XXXX....XXXXX.oXX.. ",
+" .XXXX.XXXXXX.XXXXXXX..oXXXo. ",
+" ..XX.XXX.....XXXXXX..ooXXX.. ",
+" .X......XXX.XXXXXX..ooX...X. ",
+" .XXXX.XXXXX.XXXXX..oX..XXXX. ",
+" .XXXXX..XX.XXXXX..oX.XXXXXX. ",
+" .XXXXXXX...XXXX..X..XXXXXXX. ",
+"oo.XXXXXXXXX..XX....XXXXXXXXX.oo",
+"oo.XXXXXXXXX...X...XXXXXXXXXX.oo",
+"oo.XXXXXXXX.XX...XX.XXXXXXXXX.oo",
+"oo.XXXXXXX.XXXXXXXXX.XXXXXXXX.oo",
+"oo.XXXXXX.XXXXXXXXXXX.XXXXXXX.oo",
+"oo.XXXX..XXXXXXXXXXXXX..XXXXX.oo",
+"oo.XXX.XXXXXXXXXXXXXXXXX.XXXX.oo",
+"oo.XX.XXXXXXXXXXXXXXXXXXX.XXX.oo",
+"oo...XXXXXXXXXXXXXXXXXXXXX....oo",
+"oo..XXXXXXXXXXXXXXXXXXXXXXXX..oo",
+"oo............................oo",
+"oooooooooooooooooooooooooooooooo",
+"oooooooooooooooooooooooooooooooo"};
--- /dev/null
+/* XPM */
+static char * icon-save-text_xpm[] = {
+"32 32 6 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+"o c #999999999999",
+"O c #E5E5E5E5E5E5",
+"+ c #666666666666",
+" ",
+" ",
+" ",
+" ................ ",
+" .XXXXXXXXXXXXX.X. ",
+" .XXXXXXXXXXXXX.XX. ",
+" .XXXXXXXXXXXXX.XXX. ",
+" .XXXXXXXXXXXXX..... ",
+" .XXXXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXXXX. ",
+" ..................XXXXXXXX. ",
+" .oo.OOOOOOOOOO.oo.XXXXXXXX. ",
+" .oo.OOOOOOOOOO.oo.XXXXXXXX. ",
+" .oo.OOOOOOOOOO.oo.XXXXXXXX. ",
+" .oo.OOOOOOOOOO.oo.XXXXXXXX. ",
+" .oo.OOOOOOOOOO.oo.XXXXXXXX. ",
+" .oo.OOOOOOOOOO.oo.XXXXXXXX. ",
+" .oo.OOOOOOOOOO.oo.XXXXXXXX. ",
+" .oo.OOOOOOOOOO.oo.XXXXXXXX. ",
+" .oo............oo.XXXXXXXX. ",
+" .oooooooooooooooo.XXXXXXXX. ",
+" .oooooooooooooooo.XXXXXXXX. ",
+" .oo............oo.......... ",
+" .oo.+++++++.OO.oo. ",
+" .oo.+++++++.OO.oo. ",
+" .oo.+++++++.OO.oo. ",
+" .o.+++++++.OO.oo. ",
+" ................ ",
+" "};
--- /dev/null
+/* XPM */
+static char * icon-save-mail_xpm[] = {
+"32 32 6 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+"o c #999999999999",
+"O c #E5E5E5E5E5E5",
+"+ c #666666666666",
+" ",
+" ",
+" ",
+" ........................ ",
+" ...XXXXXXXXXXXXXXXXXX... ",
+" .XX..XXXXXXXXXXXXXX..XX. ",
+" .XXXX..XXXXXXXXXX..XXXX. ",
+" .XXXXXX..XXXXXX..XXXXXX. ",
+" .XXXXXXX...XX..XXXXXXXX. ",
+" .XXXXX..XXX..XX..XXXXXX. ",
+" .XXXX.XXXXXXXXXXX.XXXXX. ",
+" .XXX.XXXXXXXXXXXXX..XXX. ",
+" .X..XXXXXXXXXXXXXXXX..X. ",
+" ..................XXXXXXXXX.. ",
+" .oo.OOOOOOOOOO.oo.XXXXXXXXXX. ",
+" .oo.OOOOOOOOOO.oo............ ",
+" .oo.OOOOOOOOOO.oo. ",
+" .oo.OOOOOOOOOO.oo. ",
+" .oo.OOOOOOOOOO.oo. ",
+" .oo.OOOOOOOOOO.oo. ",
+" .oo.OOOOOOOOOO.oo. ",
+" .oo.OOOOOOOOOO.oo. ",
+" .oo............oo. ",
+" .oooooooooooooooo. ",
+" .oooooooooooooooo. ",
+" .oo............oo. ",
+" .oo.+++++++.OO.oo. ",
+" .oo.+++++++.OO.oo. ",
+" .oo.+++++++.OO.oo. ",
+" .o.+++++++.OO.oo. ",
+" ................ ",
+" "};
--- /dev/null
+/* XPM */
+static char * icon-decode-view_xpm[] = {
+"32 32 4 1",
+" c #BFBFBFBFBFBF s backgroundToolBarColor",
+". c #000000000000",
+"X c #999999999999",
+"o c #FFFFFFFFFFFF",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ................... ",
+" .XXXXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXXXX. ",
+" .XX.............XX. ",
+" .XX.ooooooooooo.XX. ",
+" .XX.ooooooooooo.XX. ",
+" .XX.ooooooooooo.XX. ",
+" .XX.oooo.oooooo.XX. ",
+" .XX.oo..o..o.oo.XX. ",
+" .XX.o.oo.oo.ooo.XX. ",
+" .XX.ooo.ooooooo.XX. ",
+" .XX.oo.oo.ooooo.XX. ",
+" .XX.oo....ooooo.XX. ",
+" .XX.oooooo.oooo.XX. ",
+" .XX.ooooooo.ooo.XX. ",
+" .XX.ooooooooooo.XX. ",
+" .XX.ooooooooooo.XX. ",
+" .XX.ooooooooooo.XX. ",
+" .XX.ooooooooooo.XX. ",
+" .XX.............XX. ",
+" .XXXXXXXXXXXXXXXXX. ",
+" .XXXXXXXXXXXXXXXXX. ",
+" ................... ",
+" ",
+" ",
+" "};
--- /dev/null
+/* XPM */
+static char * icon-post-pic_xpm[] = {
+"32 32 4 1",
+" c #000000000000",
+". c #BFBFBFBFBFBF s backgroundToolBarColor",
+"X c #999999999999",
+"o c #FFFFFFFFFFFF",
+" ... ... ... ... ... ... ... ...",
+"................................",
+"................ ...............",
+".............. . .............",
+" ... ... ... .. .. ... ... ...",
+".......... ......... .........",
+"........ ............. .......",
+"....... ......",
+" ... .. XXXXXXXXXXXXXXXXX .. ...",
+"....... XXXXXXXXXXXXXXXXX ......",
+"....... XX XX ......",
+"....... XX ooooooooooo XX ......",
+" ... .. XX ooooooooooo XX .. ...",
+"....... XX ooooooooooo XX ......",
+"....... XX oooo oooooo XX ......",
+"....... XX oo o o oo XX ......",
+" ... .. XX o oo oo ooo XX .. ...",
+"....... XX ooo ooooooo XX ......",
+"....... XX oo oo ooooo XX ......",
+"....... XX oo ooooo XX ......",
+" ... .. XX oooooo oooo XX .. ...",
+"....... XX ooooooo ooo XX ......",
+"....... XX ooooooooooo XX ......",
+"....... XX ooooooooooo XX ......",
+" ... .. XX ooooooooooo XX .. ...",
+"....... XX ooooooooooo XX ......",
+"....... XX XX ......",
+"....... XXXXXXXXXXXXXXXXX ......",
+" ... .. XXXXXXXXXXXXXXXXX .. ...",
+"....... ......",
+"................................",
+"................................"};
--- /dev/null
+/* XPM */
+static char *gnus[] = {
+/* width height num_colors chars_per_pixel */
+" 271 273 3 1",
+/* colors */
+". s thing c #bf9900",
+"# s shadow c #ffcc00",
+"a c None",
+/* pixels */
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...aaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........######aaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.............#######aaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa................######aaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..................######aaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....................#######aaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......................#######aaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa........................#######aaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........................######aaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...........................######aaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...........aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa............................#######aaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...............aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..............................#######aaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..................aaaaaaaaaaaaaaaaaaaaaa...........aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...............................#######aaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....................aaaaaaaaaaaaaaaaaaa...............aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...............................#######aaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......................aaaaaaaaaaaaaaaa....................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa................................########aaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......................aaaaaaaaaaaaaa........................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.................................#######aaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........................aaaaaaaaaaa............................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..................................########aaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...........................aaaaaaaaa..............................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...................................#######aaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.............................aaaaaaa................................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....................................#######aaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...............................aaaaa..................................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......######.......................#######aaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa................................aaaa...................................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......aa#######aa....................#######aaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..................................aa.....................................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aa######aaaaaaa.................#######aaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....................................a......................................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......aa#####aaaaaaaaa................#######aaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.............................................................................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaa...............#######aaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..............................................................................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......aa######aaaaaaaaaa...............#######aaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa................................................................................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......aa#####aaaaaaaaaaaa..............#######aaaaa",
+"aaaaaaaaa..aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..................................................................................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a######aaaaaaaaaaaa..............#######aaaaa",
+"aaaaaaaaa....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....................................................................................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a######aaaaaaaaaaaaa.............#######aaaaa",
+"aaaaaaaa.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaa..............####....................................................................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a#######aaaaaaaaaaaaa............########aaaaa",
+"aaaaaaa.........aaaaaaaaaaaaaaaaaaaaaaaaaaa.............########...................................................................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a#######aaaaaaaaaaaaaa...........########aaaaa",
+"aaaaaaa...........aaaaaaaaaaaaaaaaaaaaaaa.............############..................................................................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a######aaaaaaaaaaaaaaa...........########aaaaa",
+"aaaaaaaa..........aaaaaaaaaaaaaaaaaaaaaa.............##############..................................................................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a#######aaaaaaaaaaaaaaa...........########aaaaa",
+"aaaaaaaa...........aaaaaaaaaaaaaaaaaaaa............##################.......................##########................................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aa######aaaaaaaaaaaaaaaa..........########aaaaa",
+"aaaaaaaa............aaaaaaaaaaaaaaaaaa............####################....................###############..............................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....aaa#####aaaaaaaaaaaaaaaaa..........#######aaaaaa",
+"aaaaaaaa............aaaaaaaaaaaaaaaa..............#####################.................#####################..........................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..aaaaaa..aaaaa###aaaaaaaaaaaaaaaaaa..........#######aaaaaa",
+"aaaaaaaa.............aaaaaaaaaaaaaa..............#######################...............#######################..........................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..aaaaaa..aaaaa##aaaaaaaaaaaaaaaaaaa..........#######aaaaaa",
+"aaaaaaaaa.............aaaaaaaaaaa...............##########aa#############.............#########################..........................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...aaaaaaaaaaaaa##aaaaaaaaaaaaaaaaaaa..........#######aaaaaa",
+"aaaaaaaaa.............aaaaaaaaa................#########aaaaaaa###########............##########################..........................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........########aaaaaa",
+"aaaaaaaaa................aaaa..................#######aaaaaaaaaa###########..........############################..........................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........########aaaaaa",
+"aaaaaaaaa.....................................######aaaaaaaaaaaaa###########.........#############################..........................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........########aaaaaa",
+"aaaaaaaaa....................................######aaaaaaaaaaaaaaaa#########........###############################.........................aaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........########aaaaaa",
+"aaaaaaaaaa.................................#######aaaaaaaaaaaaaaaaaa#########.......#######aaaaaaaaaaa##############..........................aaaaaaaaaaaaaaaaaaaaaaaaaaa.....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#######aaaaaaa",
+"aaaaaaaaaa................................#######aaaaaaaaaaaaaaaaaaaa########......#####aaaaaaaaaaaaaaaaa############..........................aaaaaaaaaaaaaaaaaaaaaaaaa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#######aaaaaaa",
+"aaaaaaaaaa...............................########aaaaaaaaaaaaaaaaaaaaa########....#####aaaaaaaaaaaaaaaaaaaaa##########..........................aaaaaaaaaaaaaaaaaaaaaaa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....a#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#######aaaaaaa",
+"aaaaaaaaa#..............................########aaaaaaaaaaaaaaaaaaaaaaaa#.####...#####aaaaaaaaaaaaaaaaaaaaaaa##########...........................aaaaaaaaaaaaaaaaaaaa.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....aa###aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#######aaaaaaa",
+"aaaaaaaaa#.............................########aaaaaaaaaaaaaaaaaaaaaaaaa...###..######aaaaaaaaaaaaaaaaaaaaaaaa##########...........................aaaaaaaaaaaaaaaaaaa......a#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....a####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........########aaaaaaa",
+"aaaaaaaa###...........................#########aaaaaaaaaaaaaaaaaaaaaaaa....##########aaaaaaaaaaaaaaaaaaaaaaaaaa##########............................aaaaaaaaaaaaaaa........##aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aa###aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........########aaaaaaa",
+"aaaaaaaa###..........................#########aaaaaaaaaaaaaaaaaaaaaaaaa....#########aaaaaaaaaaaaaaaaaaaaaaaaaaaa##########...............................aaaaaaaa...........##aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........########aaaaaaa",
+"aaaaaaaa###.........................#########aaaaaaaaaaaaaaaaaaaaaaaaa....a#########aaaaaaaaaaaaaaaaaaaaaaaaaaaaa##########................................................##aaaaaa...aaaaaaaaaaaaaaaaaaaaa......a#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#######aaaaaaaa",
+"aaaaaaa####........................#########aaaaaaaaaaaaaaaaaaaaaaaaa....aaa#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#########...............................................##aaaaaa....aaaaaaaaaaaaaaaaaaa.......a#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#######aaaaaaaa",
+"aaaaaaa####.......................########aaaaaaaaaaaaaaaaaaaaaaaaaa.....aaa#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#########..............................................##aaaaa.....aaaaaaaaaaaaaaaaaa.......a#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#######aaaaaaaa",
+"aaaaaa######....................#########aaaaaaaaaaaaaaaaaaaaaaaaaa.....a#aaa#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#########............................................##aaaaaa......aaaaaaaaaaaaaaa.........a#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#######aaaaaaaa",
+"aaaaaa######...................#########aaaaaaaaaaaaaaaaaaaaaaaaaa......##aaa####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#########...........................................##aaaaa.......aaaaaaaaaaaaa..........aa####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#######aaaaaaaa",
+"aaaaaa#######.................#########aaaaaaaaaaaaaaaaaaaaaaaaaaa.....a###aaa###aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#########.........................................###aaaaa.........aaaaaaa..............a#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa........########aaaaaaaa",
+"aaaaaaa#######...............#########aaaaaaaaaaaaaaaaaaaaaaaaaaa.....a####aaa##aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#########........................................##aaaaa...............................a####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#######aaaaaaaaa",
+"aaaaaaa########............##########aaaaaaaaaaaaaaaaaaaaaaaaaaa.....a####aaaa#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#########.......................................##aaaaa...............................#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#######aaaaaaaaa",
+"aaaaaaaa##########.......###########aaaaaaaaaaaaaaaaaaaaaaaaaaa......#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#########.....................................###aaaaa..............................#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#######aaaaaaaaa",
+"aaaaaaaaa##########################aaaaaaaaaaaaaaaaaaaaaaaaaaaa.....#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#########....................................##aaaaa...............................#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa........########aaaaaaaaa",
+"aaaaaaaaa#########################aaaaaaaaaaaaaaaaaaaaaaaaaaaa.....#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#########..................................###aaaaa..............................#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa........#######aaaaaaaaaa",
+"aaaaaaaaaa#######################aaaaaaaaaaaaaaaaaaaaaaaaaaaa.....a#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#########...............................####aaaaa..............................######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa........#######aaaaaaaaaa",
+"aaaaaaaaaaa#####################aaaaaaaaaaaaaaaaaaaaaaaaaaaaa....a#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#########.............................#####aaaaa.............................#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa........#######aaaaaaaaaa",
+"aaaaaaaaaaa###################aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#########...........................######aaaa..............................######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......########aaaaaaaaaa",
+"aaaaaaaaaaaa#################aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#########.........................######aaaaa.............................#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa........#######aaaaaaaaaaa",
+"aaaaaaaaaaaaa###############aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....a#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...aaaaaaaaaaaaaaaaa#########.......................#######aaaa.............................#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa........#######aaaaaaaaaaa",
+"aaaaaaaaaaaaaaa###########aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....a#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......aaaaaaaaaaaaaaaa#########....................#########aaaa............................########aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a#######aaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaa###aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....a#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......aaaaaaaaaaaaaaaa#########..................#########aaaaa..........................#########aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......#######aaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........aaaaaaaaaaaaaaa###########.............###########aaaaa.........................##########aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......#######aaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....a#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa............aaaaaaaaaaaaaaa##############....###############aaaaaaa.......................##########aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a#######aaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....a#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.............aaaaaaaaaaaaaaa##############################aaaaaaaaa.....................############aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a######aaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...............aaaaaaaaaaaaaaa############################aaaaaaaaaaa...................############aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a######aaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....a#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaa................aaaaaaaaaaaaaaaa##########################aaaaaaaaaaaa#................#############aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......#######aaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....a#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....aaaaaa.................aaaaaaaaaaaaaaaa########################aaaaaaaaaaaaa##..............#############aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a#######aaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aaaaa...................aaaaaaaaaaaaaaaa######################aaaaaaaaaaaaa#####.........###############aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a######aaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....a#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aaaaa....................aaaaaaaaaaaaaaaaa###################aaaaaaaaaaaaaaa########..##################aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a######aaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....a#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aaaaaa....................aaaaaaaaaaaaaaaaaaa################aaaaaaaaaaaaaaaa###########################aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a#######aaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......aaaaa......................aaaaaaaaaaaaaaaaaaaaa###########aaaaaaaaaaaaaaaaaa##########################aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....a####aaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......aaaaa.......................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa########################aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....a#####aaaaaaaaaaaaaaaaaaaaaaaaaaaa.......aaaaaa.......................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######################aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a######aaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....#####aaaaaaaaaaaaaaaaaaaaaaaaaaaa........a###a.........................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa####################aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a#######aaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....a####aaaaaaaaaaaaaaaaaaaaaaaaaaaa........a####a.........................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa##################aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....a#####aaaaaaaaaaaaaaaaaaaaaaaaaaa........a#####aaa.......................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa###############aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....a####aaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaa#.....................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa############aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aa######aaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....a####aaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaa##....................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....#####aaaaaaaaaaaaaaaaaaaaaaaaa..........######aaaaa#####..................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....a####aaaaaaaaaaaaaaaaaaaaaaaaa...........#####aaaaa#######..................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....####aaaaaaaaaaaaaaaaaaaaaaaaa...........#####aaaaaa#######..................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......aa#####aaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....####aaaaaaaaaaaaaaaaaaaaaaaaa...........######aaaaa#########.................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....####aaaaaaaaaaaaaaaaaaaaaaaa...........######aaaaa###########................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....####aaaaaaaaaaaaaaaaaaaaaaa............#######aaaaaaa##########...............aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......aa######aaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......####aaaaaaaaaaaaaaaaaaaaaa............#######aaaaaaaaa#########...............aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......aa#####aaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....####aaaaaaaaaaaaaaaaaaaaaa............#######aaaaaaaaaaaa########..............aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......###aaaaaaaaaaaaaaaaaaaaa............#########aaaaaaaaaaaaa#######..............aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......aa#####aaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......###aaaaaaaaaaaaaaaaaaa.............#########aaaaaaaaaaaaaaa#######.............aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......aa#####aaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa........#aaaaaaaaaaaaaaaaaaa.............#########aaaaaaaaaaaaaaaaa######.............aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aa######aaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa........#aaaaaaaaaaaaaaaaa..............#########aaaaaaaaaaaaaaaaaaa#####.............aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......aa#####aaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa........#aaaaaaaaaaaaaaa...............#########aaaaaaaaaaaaaaaaaaaa#####.............aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aaa#####aaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...........aaaaaaaaaaaaa...............#########aaaaaaaaaaaaaaaaaaaaaa#####............aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aa######aaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...............aaaaa..................########aaaaaaaaaaaaaaaaaaaaaaaaa####............aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......aa#####aaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......................................########aaaaaaaaaaaaaaaaaaaaaaaaaa####...........aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aaa#####aaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....................................########aaaaaaaaaaaaaaaaaaaaaaaaaaaa###...........aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aaa####aaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....................................#########aaaaaaaaaaaaaaaaaaaaaaaaaaaaa####..........aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....aaa#####aaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...................................#########aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa###..........aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aaa#####aaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...................................#########aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa###..........aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aaa#####aaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.................................#########aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa###..........aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aaa####aaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa................................#########aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa##..........aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....aaa#####aaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa................................#########aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa##..........aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aaa#####aaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..............................##########aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#..........aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa###aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aaa#####aaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.............................##########aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#.........#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa###aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aaa####aaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa............................##########aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#.........#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa###aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....aaa#####aaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...........................#########aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#.........#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aaa#####aaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........................##########aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#........##aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa####aaaa..aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aa######aaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......................###########aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#........##aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#####aaa...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......aa#####aaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#...................############aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#........#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#####aaa...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......aa#####aaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa##................#############aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#.......##aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aa....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aa######aaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa###............##############aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#......###aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aa....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......aa######aaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa####.........###############aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#......###aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aa.....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......aa######aaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######..###################aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#.....###aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aa....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#########################aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#.....###aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#######a.....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......aa######aaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa########################aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#.....###aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aa.....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a#######aaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#####################aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#....####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#######a......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a#######aaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa##################aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#....###aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######a.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa##############aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#...####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aa.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a#######aaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa###########aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa##..####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#######a.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a#######aaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aa.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aa.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aa.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#####aaa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......aa######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#####aaa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......aa######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa##aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#####aaa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......aa######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#####aaa.....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......aa#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aaa.....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#####aaa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aaa.....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#####aaa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#####aaa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#####aaa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aaa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa######aaa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#######aa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....a#aaaaaaaaaaaaaaaaaaaaaa#aaaaaaaaaaaaa#######aaa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....#aaaaaaaaaaaaaaaaaaaaaa###aaaaaaaaaaaa#######aa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......#aaaaaaaaaaaaaaaaaaaaa#####aaaaaaaaaa########a.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......#aaaaaaaaaaaaaaaaaaaaa#####aaaaaaaaa########a.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......#aaaaaaaaaaaaaaaaaaaa#######aaaaaaa#########a.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......##aaaaaaaaaaaaaaaaaaa########a..aa##########a.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa........##aaaaaaaaaaaaaaaaaa#########....##########a........aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa........#aaaaaaaaaaaaaaaaaa#########......#########........aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#aaaaaaaaaaaaaaaaaa#########......########a........aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........##aaaaaaaaaaaaaaaaa#########.......#######.........aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........##aaaaaaaaaaaaaaaaa########.........#####.........aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........###aaaaaaaaaaaaaaaa########........................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........###aaaaaaaaaaaaaaaaa########.......................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........###aaaaaaaaaaaaaaaa########.......................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........####aaaaaaaaaaaaaaa#########.......................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaa########.......................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........####aaaaaaaaaaaaaaa#########......................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaa#########......................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaa########.......................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaa#########......................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaa########.......................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaa########.......................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaa########.......................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaa########.......................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......a######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaa#######........................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......aa######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaa########.......................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......a#######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........####aaaaaaaaaaaaaaaaa#######.........a..............aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aa######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaa#######a........aaa............aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....aa######aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaa#######........aaaaa..........aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....aaa#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........####aaaaaaaaaaaaaaaaa#######a.......aaaaaaa.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....aaa#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaa######a........aaaaaaa.....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...aaaaa###aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaa#######a.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...aaaaa###aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaaa#######........aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..aaaaaa##aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaa#######a.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaa##aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaaa#######.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaaaa######a.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaa#######a......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaaaa#######.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaaaa#######a.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........####aaaaaaaaaaaaaaaaaaaa#######.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaa#######a.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaaaaa######aa.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........####aaaaaaaaaaaaaaaaaaaaa######a.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaa######aa.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaaaaaa######a.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaaaaaaa#####aa.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaaaa####aa.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaaaaaaa#####aa.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaaaaaaaa####aaa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaaaaa####aa.......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaaaaaa###aaa......aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaaaaaaaaa####aaa.....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........####aaaaaaaaaaaaaaaaaaaaaaaaa####aaa....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaaaaaaa###aaa.....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaaaaaaaaaaa###aaa....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........####aaaaaaaaaaaaaaaaaaaaaaaaaa####aaa....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaaaaaaaa###aaaa....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaaaaaaaaa###aaa....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaa##aaaa....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaa#aaaaa....aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa........#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa......#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.....#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...#####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..a####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..a####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.a####aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa###aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aa###aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa###aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa##aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa##aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa##aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+};
@c Insert "\input texinfo" at 1st line before texing this file alone.
@c -*-texinfo-*-
-@c Copyright (C) 1995 Free Software Foundation, Inc.
+@c Copyright (C) 1995, 2001 Free Software Foundation, Inc.
@setfilename gnus-faq.info
@node Frequently Asked Questions
This is the Gnus Frequently Asked Questions list.
If you have a Web browser, the official hypertext version is at
-@file{http://www.ccs.neu.edu/software/gnus/}, and has
+@uref{http://www.ccs.neu.edu/software/contrib/gnus/}, and has
probably been updated since you got this manual.
@menu
@itemize @minus
@item
-@file{ftp://ftp.ifi.uio.no/pub/emacs/gnus/gnus.tar.gz}
+@uref{ftp://ftp.ifi.uio.no/pub/emacs/gnus/gnus.tar.gz}
@item
-@file{ftp://ftp.pilgrim.umass.edu/pub/misc/ding/}
+@uref{ftp://ftp.pilgrim.umass.edu/pub/misc/ding/}
@item
@file{gopher://gopher.pilgrim.umass.edu/11/pub/misc/ding/}
@item
-@file{ftp://aphrodite.nectar.cs.cmu.edu/pub/ding-gnus/}
+@uref{ftp://aphrodite.nectar.cs.cmu.edu/pub/ding-gnus/}
@item
-@file{ftp://ftp.solace.mh.se:/pub/gnu/elisp/}
+@uref{ftp://ftp.solace.mh.se:/pub/gnu/elisp/}
@end itemize
If you have Gnu Emacs 19.28 or earlier, or XEmacs 19.12 or earlier, get
a recent version of auc-menu.el from
-@file{ftp://ftp.iesd.auc.dk/pub/emacs-lisp/auc-menu.el}, and install it
+@uref{ftp://ftp.iesd.auc.dk/pub/emacs-lisp/auc-menu.el}, and install it
under the name easymenu.el somewhere early in your load path.
list is mainly for developers and testers.
Gnus has a home World Wide Web page at@*
-@file{http://www.ifi.uio.no/~larsi/ding.html}.
+@uref{http://www.ifi.uio.no/~larsi/ding.html}.
Gnus has a write up in the X Windows Applications FAQ at@*
-@file{http://www.ee.ryerson.ca:8080/~elf/xapps/Q-III.html}.
+@uref{http://www.ee.ryerson.ca:8080/~elf/xapps/Q-III.html}.
The Gnus manual is also available on the World Wide Web. The canonical
source is in Norway at@*
-@file{http://www.ifi.uio.no/~larsi/ding-manual/gnus_toc.html}.
+@uref{http://www.ifi.uio.no/~larsi/ding-manual/gnus_toc.html}.
There are three mirrors in the United States:
@enumerate
@item
-@file{http://www.miranova.com/gnus-man/}
+@uref{http://www.miranova.com/gnus-man/}
@item
-@file{http://www.pilgrim.umass.edu/pub/misc/ding/manual/gnus_toc.html}
+@uref{http://www.pilgrim.umass.edu/pub/misc/ding/manual/gnus_toc.html}
@item
-@file{http://www.rtd.com/~woo/gnus/}
+@uref{http://www.rtd.com/~woo/gnus/}
@end enumerate
PostScript copies of the Gnus Reference card are available from@*
-@file{ftp://ftp.cs.ualberta.ca/pub/oolog/gnus/}. They are mirrored at@*
-@file{ftp://ftp.pilgrim.umass.edu/pub/misc/ding/refcard/} in the
+@uref{ftp://ftp.cs.ualberta.ca/pub/oolog/gnus/}. They are mirrored at@*
+@uref{ftp://ftp.pilgrim.umass.edu/pub/misc/ding/refcard/} in the
United States. And@*
-@file{ftp://marvin.fkphy.uni-duesseldorf.de/pub/gnus/}
+@uref{ftp://marvin.fkphy.uni-duesseldorf.de/pub/gnus/}
in Germany.
An online version of the Gnus FAQ is available at@*
-@file{http://www.miranova.com/~steve/gnus-faq.html}. Off-line formats
+@uref{http://www.miranova.com/~steve/gnus-faq.html}. Off-line formats
are also available:@*
-ASCII: @file{ftp://ftp.miranova.com/pub/gnus/gnus-faq}@*
-PostScript: @file{ftp://ftp.miranova.com/pub/gnus/gnus-faq.ps}.
+ASCII: @uref{ftp://ftp.miranova.com/pub/gnus/gnus-faq}@*
+PostScript: @uref{ftp://ftp.miranova.com/pub/gnus/gnus-faq.ps}.
@item
Mailcrypt is an Emacs interface to PGP. It works, it installs
without hassle, and integrates very easily. Mailcrypt can be
obtained from@*
-@file{ftp://cag.lcs.mit.edu/pub/patl/mailcrypt-3.4.tar.gz}.
+@uref{ftp://cag.lcs.mit.edu/pub/patl/mailcrypt-3.4.tar.gz}.
@item
Tools for Mime.
be prepared to move the byte-compiled code somewhere. There
are currently two versions of this package available. It can
be obtained from@*
-@file{ftp://ftp.jaist.ac.jp/pub/GNU/elisp/}.
+@uref{ftp://ftp.jaist.ac.jp/pub/GNU/elisp/}.
Be sure to apply the supplied patch. It works with Gnus through
version 5.0.9. In order for all dependencies to work correctly
the load sequence is as follows:
(("xref"
("alt.fan.oj-simpson" -1000 nil s))
("subject"
- ("\\<\\(make\\|fast\\|big\\)\\s-*\\(money\\|cash\\|bucks?\\)\\>" -1000 nil r)
+ (concat "\\<\\(make\\|fast\\|big\\)\\s-*"
+ "\\(money\\|cash\\|bucks?\\)\\>"
+ -1000 nil r)
("$$$$" -1000 nil s)))
@end lisp
;; $$$ Make Money $$$
("$$" -10 nil s)
;; Empty subjects are worthless!
- ("^ *\\([(<]none[>)]\\|(no subject\\( given\\)?)\\)? *$" -10 nil r)
+ ("^ *\\([(<]none[>)]\\|(no subject\\( given\\)?)\\)? *$"
+ -10 nil r)
;; Sometimes interesting announces occur!
("ANN?OU?NC\\(E\\|ING\\)" +10 nil r)
;; Some people think they're on mailing lists
("\\(un\\)?sub?scribe" -100 nil r)
;; Stop Micro$oft NOW!!
- ("\\(m\\(icro\\)?[s$]\\(oft\\|lot\\)?-?\\)?wind?\\(ows\\|aube\\|oze\\)?[- ]*\\('?95\\|NT\\|3[.]1\\|32\\)" -1001 nil r)
+ ;; ("concat" used to avoid overfull box.)
+ (concat "\\(m\\(icro\\)?[s$]\\(oft\\|lot\\)?-?\\)?"
+ "wind?\\(ows\\|aube\\|oze\\)?[- ]*"
+ "\\('?95\\|NT\\|3[.]1\\|32\\)" -1001 nil r)
;; I've nothing to buy
("\\(for\\|4\\)[- ]*sale" -100 nil r)
;; SELF-DISCIPLINED people
("^xref: \\S-+ \\S-+ \\S-+ \\S-+ \\S-+" -2 nil r)
("^xref: \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+" -4 nil r)
("^xref: \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+" -8 nil r)
- ("^xref: \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+" -16 nil r)
- ("^xref: \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+" -32 nil r)
- ("^xref: \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+" -64 nil r)
- ("^xref: \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+" -128 nil r)
- ("^xref: \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+" -256 nil r)
- ("^xref: \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+" -512 nil r))
+ ("^xref: \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+"
+ -16 nil r)
+ (concat "^xref: \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+"
+ " \\S-+ \\S-+"
+ -32 nil r)
+ (concat "^xref: \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+"
+ " \\S-+ \\S-+ \\S-+" -64 nil r)
+ (concat "^xref: \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+"
+ " \\S-+ \\S-+ \\S-+ \\S-+" -128 nil r)
+ (concat "^xref: \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+"
+ " \\S-+ \\S-+ \\S-+ \\S-+ \\S-+" -256 nil r)
+ (concat "^xref: \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+ \\S-+"
+ " \\S-+" \\S-+ \\S-+ \\S-+ \\S-+ \\S-+" -512 nil r))
@end lisp
@end enumerate
@example
(defconst mail-yank-ignored-headers
"^.*:"
- "Delete these headers from old message when it's inserted in a reply.")
+ "Delete these headers from message when it's inserted in reply.")
@end example
@item
Q3.1 How do I convert my kill files to score files?
-A kill-to-score translator was written by Ethan Bradford
-<ethanb@@ptolemy.astro.washington.edu>. It is available from@*
-@file{http://baugi.ifi.uio.no/~larsi/ding-various/gnus-kill-to-score.el}.
+@samp{ethanb@@ptolemy.astro.washington.edu, Ethan Bradford} write a
+kill-to-score translator. It is available from@*
+@uref{http://baugi.ifi.uio.no/~larsi/ding-various/gnus-kill-to-score.el}.
@item
This is what I use...customize as necessary...
@lisp
-;;; Don't auto-select first article if reading sources, or archives or
-;;; jobs postings, etc. and just display the summary buffer
+;;; Don't auto-select first article if reading sources, or
+;;; archives or jobs postings, etc. and just display the
+;;; summary buffer
(add-hook 'gnus-select-group-hook
(function
(lambda ()
line in the body of the message: @emph{get misc gnus-bbdb.el}.
Or get it from the World Wide Web:@*
-@file{http://www.cs.ubc.ca/spider/edmonds/gnus-bbdb.el}.
+@uref{http://www.cs.ubc.ca/spider/edmonds/gnus-bbdb.el}.
@end itemize
-\input texinfo @c -*-texinfo-*- -*- coding: iso-latin-1 -*-
+\input texinfo
@setfilename gnus
@settitle Gnus Manual
\usepackage[latin1]{inputenc}
\usepackage{pagestyle}
\usepackage{epsfig}
-\usepackage{bembo}
\usepackage{pixidx}
+\input{gnusconfig.tex}
+
+\ifx\pdfoutput\undefined
+\else
+\usepackage[pdftex,bookmarks]{hyperref}
+\pdfcompresslevel=9
+\fi
\makeindex
\begin{document}
+\newcommand{\gnusversionname}{Oort Gnus v.}
\newcommand{\gnuschaptername}{}
\newcommand{\gnussectionname}{}
\newcommand{\gnusbackslash}{/}
+\newcommand{\gnusref}[1]{``#1'' on page \pageref{#1}}
+\ifx\pdfoutput\undefined
+\newcommand{\gnusuref}[1]{\gnustt{#1}}
+\else
+\newcommand{\gnusuref}[1]{\href{#1}{\gnustt{#1}}}
+\fi
\newcommand{\gnusxref}[1]{See ``#1'' on page \pageref{#1}}
\newcommand{\gnuspxref}[1]{see ``#1'' on page \pageref{#1}}
\newcommand{\gnuskindex}[1]{\index{#1}}
\newcommand{\gnusindex}[1]{\index{#1}}
-\newcommand{\gnustt}[1]{{\fontfamily{pfu}\fontsize{10pt}{10}\selectfont #1}}
+\newcommand{\gnustt}[1]{{\gnusselectttfont{}#1}}
\newcommand{\gnuscode}[1]{\gnustt{#1}}
-\newcommand{\gnussamp}[1]{``{\fontencoding{OT1}\fontfamily{pfu}\fontsize{10pt}{10}\selectfont #1}''}
+\newcommand{\gnussamp}[1]{``{\fontencoding{OT1}\gnusselectttfont{}#1}''}
\newcommand{\gnuslisp}[1]{\gnustt{#1}}
\newcommand{\gnuskbd}[1]{`\gnustt{#1}'}
\newcommand{\gnusfile}[1]{`\gnustt{#1}'}
\newcommand{\gnusvar}[1]{{\fontsize{10pt}{10}\selectfont\textsl{\textsf{#1}}}}
\newcommand{\gnussc}[1]{\textsc{#1}}
\newcommand{\gnustitle}[1]{{\huge\textbf{#1}}}
+\newcommand{\gnusversion}[1]{{\small\textit{#1}}}
\newcommand{\gnusauthor}[1]{{\large\textbf{#1}}}
\newcommand{\gnusresult}[1]{\gnustt{=> #1}}
\newcommand{\gnusbraceleft}{{$>$}}
\newcommand{\gnusbraceright}{{$>$}}
-\newcommand{\gnushead}{\raisebox{-1cm}{\epsfig{figure=ps/gnus-head.eps,height=1cm}}}
+\newcommand{\gnushead}{\raisebox{-1cm}{\epsfig{figure=ps/gnus-head,height=1cm}}}
\newcommand{\gnusinteresting}{
\marginpar[\mbox{}\hfill\gnushead]{\gnushead}
}
}
\newcommand{\gnusicon}[1]{
-\marginpar[\mbox{}\hfill\raisebox{-1.5cm}{\epsfig{figure=tmp/#1-up.ps,height=1.5cm}}]{\raisebox{-1cm}{\epsfig{figure=tmp/#1-up.ps,height=1cm}}}
+\marginpar[\mbox{}\hfill\raisebox{-1.5cm}{\epsfig{figure=ps/#1-up,height=1.5cm}}]{\raisebox{-1cm}{\epsfig{figure=ps/#1-up,height=1cm}}}
}
\newcommand{\gnuspicon}[1]{
{
\ifodd\count0
\mbox{} \hfill
-\raisebox{-0.5cm}{\epsfig{figure=ps/gnus-big-logo.eps,height=1cm}}
+\raisebox{-0.5cm}{\epsfig{figure=ps/gnus-big-logo,height=1cm}}
\else
-\raisebox{-0.5cm}{\epsfig{figure=ps/gnus-big-logo.eps,height=1cm}}
+\raisebox{-0.5cm}{\epsfig{figure=ps/gnus-big-logo,height=1cm}}
\hfill \mbox{}
\fi
}
{
\ifodd\count0
\mbox{} \hfill
-\raisebox{-0.5cm}{\epsfig{figure=ps/gnus-big-logo.eps,height=1cm}}
+\raisebox{-0.5cm}{\epsfig{figure=ps/gnus-big-logo,height=1cm}}
\else
-\raisebox{-0.5cm}{\epsfig{figure=ps/gnus-big-logo.eps,height=1cm}}
+\raisebox{-0.5cm}{\epsfig{figure=ps/gnus-big-logo,height=1cm}}
\hfill \mbox{}
\fi
}
{
\ifodd\count0
\mbox{} \hfill
-\raisebox{-0.5cm}{\epsfig{figure=ps/gnus-big-logo.eps,height=1cm}}
+\raisebox{-0.5cm}{\epsfig{figure=ps/gnus-big-logo,height=1cm}}
\else
-\raisebox{-0.5cm}{\epsfig{figure=ps/gnus-big-logo.eps,height=1cm}}
+\raisebox{-0.5cm}{\epsfig{figure=ps/gnus-big-logo,height=1cm}}
\hfill \mbox{}
\fi
}
\parindent=0cm
\addtolength{\textheight}{2cm}
-\gnustitle{\gnustitlename}\\
+\gnustitle{\gnustitlename}\hfill\gnusversion{\gnusversionname}\\
\rule{15cm}{1mm}\\
\vfill
-\hspace*{0cm}\epsfig{figure=ps/gnus-big-logo.eps,height=15cm}
+\hspace*{0cm}\epsfig{figure=ps/gnus-big-logo,height=15cm}
\vfill
\rule{15cm}{1mm}\\
\gnusauthor{by Lars Magne Ingebrigtsen}
\thispagestyle{empty}
-Copyright \copyright{} 1995, 1996, 1997, 1998, 1999, 2000
+Copyright \copyright{} 1995, 1996, 1997, 1998, 1999, 2000, 2001
Free Software Foundation, Inc.
This file documents Gnus, the GNU Emacs newsreader.
-Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001
+ Free Software Foundation, Inc.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.1 or
@page
@vskip 0pt plus 1filll
-Copyright @copyright{} 1995, 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+Copyright @copyright{} 1995, 1996, 1997, 1998, 1999, 2000, 2001
+ Free Software Foundation, Inc.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.1 or
@end iftex
@menu
-* Starting Up:: Finding news can be a pain.
-* Group Buffer:: Selecting, subscribing and killing groups.
-* Summary Buffer:: Reading, saving and posting articles.
-* Article Buffer:: Displaying and handling articles.
-* Composing Messages:: Information on sending mail and news.
-* Select Methods:: Gnus reads all messages from various select methods.
-* Scoring:: Assigning values to articles.
-* Various:: General purpose settings.
-* The End:: Farewell and goodbye.
-* Appendices:: Terminology, Emacs intro, FAQ, History, Internals.
-* Index:: Variable, function and concept index.
-* Key Index:: Key Index.
+* Starting Up:: Finding news can be a pain.
+* Group Buffer:: Selecting, subscribing and killing groups.
+* Summary Buffer:: Reading, saving and posting articles.
+* Article Buffer:: Displaying and handling articles.
+* Composing Messages:: Information on sending mail and news.
+* Select Methods:: Gnus reads all messages from various select methods.
+* Scoring:: Assigning values to articles.
+* Various:: General purpose settings.
+* The End:: Farewell and goodbye.
+* Appendices:: Terminology, Emacs intro, FAQ, History, Internals.
+* Index:: Variable, function and concept index.
+* Key Index:: Key Index.
@detailmenu
--- The Detailed Node Listing ---
Starting Gnus
-* Finding the News:: Choosing a method for getting news.
-* The First Time:: What does Gnus do the first time you start it?
-* The Server is Down:: How can I read my mail then?
-* Slave Gnusae:: You can have more than one Gnus active at a time.
-* Fetching a Group:: Starting Gnus just to read a group.
-* New Groups:: What is Gnus supposed to do with new groups?
-* Startup Files:: Those pesky startup files---@file{.newsrc}.
-* Auto Save:: Recovering from a crash.
-* The Active File:: Reading the active file over a slow line Takes Time.
-* Changing Servers:: You may want to move from one server to another.
-* Startup Variables:: Other variables you might change.
+* Finding the News:: Choosing a method for getting news.
+* The First Time:: What does Gnus do the first time you start it?
+* The Server is Down:: How can I read my mail then?
+* Slave Gnusae:: You can have more than one Gnus active at a time.
+* Fetching a Group:: Starting Gnus just to read a group.
+* New Groups:: What is Gnus supposed to do with new groups?
+* Changing Servers:: You may want to move from one server to another.
+* Startup Files:: Those pesky startup files---@file{.newsrc}.
+* Auto Save:: Recovering from a crash.
+* The Active File:: Reading the active file over a slow line Takes Time.
+* Startup Variables:: Other variables you might change.
New Groups
-* Checking New Groups:: Determining what groups are new.
-* Subscription Methods:: What Gnus should do with new groups.
-* Filtering New Groups:: Making Gnus ignore certain new groups.
+* Checking New Groups:: Determining what groups are new.
+* Subscription Methods:: What Gnus should do with new groups.
+* Filtering New Groups:: Making Gnus ignore certain new groups.
Group Buffer
-* Group Buffer Format:: Information listed and how you can change it.
-* Group Maneuvering:: Commands for moving in the group buffer.
-* Selecting a Group:: Actually reading news.
-* Group Data:: Changing the info for a group.
-* Subscription Commands:: Unsubscribing, killing, subscribing.
-* Group Levels:: Levels? What are those, then?
-* Group Score:: A mechanism for finding out what groups you like.
-* Marking Groups:: You can mark groups for later processing.
-* Foreign Groups:: Creating and editing groups.
-* Group Parameters:: Each group may have different parameters set.
-* Listing Groups:: Gnus can list various subsets of the groups.
-* Sorting Groups:: Re-arrange the group order.
-* Group Maintenance:: Maintaining a tidy @file{.newsrc} file.
-* Browse Foreign Server:: You can browse a server. See what it has to offer.
-* Exiting Gnus:: Stop reading news and get some work done.
-* Group Topics:: A folding group mode divided into topics.
-* Misc Group Stuff:: Other stuff that you can to do.
+* Group Buffer Format:: Information listed and how you can change it.
+* Group Maneuvering:: Commands for moving in the group buffer.
+* Selecting a Group:: Actually reading news.
+* Subscription Commands:: Unsubscribing, killing, subscribing.
+* Group Data:: Changing the info for a group.
+* Group Levels:: Levels? What are those, then?
+* Group Score:: A mechanism for finding out what groups you like.
+* Marking Groups:: You can mark groups for later processing.
+* Foreign Groups:: Creating and editing groups.
+* Group Parameters:: Each group may have different parameters set.
+* Listing Groups:: Gnus can list various subsets of the groups.
+* Sorting Groups:: Re-arrange the group order.
+* Group Maintenance:: Maintaining a tidy @file{.newsrc} file.
+* Browse Foreign Server:: You can browse a server. See what it has to offer.
+* Exiting Gnus:: Stop reading news and get some work done.
+* Group Topics:: A folding group mode divided into topics.
+* Misc Group Stuff:: Other stuff that you can to do.
Group Buffer Format
-* Group Line Specification:: Deciding how the group buffer is to look.
-* Group Modeline Specification:: The group buffer modeline.
-* Group Highlighting:: Having nice colors in the group buffer.
+* Group Line Specification:: Deciding how the group buffer is to look.
+* Group Modeline Specification:: The group buffer modeline.
+* Group Highlighting:: Having nice colors in the group buffer.
Group Topics
-* Topic Variables:: How to customize the topics the Lisp Way.
-* Topic Commands:: Interactive E-Z commands.
-* Topic Sorting:: Sorting each topic individually.
-* Topic Topology:: A map of the world.
-* Topic Parameters:: Parameters that apply to all groups in a topic.
+* Topic Variables:: How to customize the topics the Lisp Way.
+* Topic Commands:: Interactive E-Z commands.
+* Topic Sorting:: Sorting each topic individually.
+* Topic Topology:: A map of the world.
+* Topic Parameters:: Parameters that apply to all groups in a topic.
Misc Group Stuff
-* Scanning New Messages:: Asking Gnus to see whether new messages have arrived.
-* Group Information:: Information and help on groups and Gnus.
-* Group Timestamp:: Making Gnus keep track of when you last read a group.
-* File Commands:: Reading and writing the Gnus files.
+* Scanning New Messages:: Asking Gnus to see whether new messages have arrived.
+* Group Information:: Information and help on groups and Gnus.
+* Group Timestamp:: Making Gnus keep track of when you last read a group.
+* File Commands:: Reading and writing the Gnus files.
+* Sieve Commands:: Managing Sieve scripts.
Summary Buffer
* Choosing Articles:: Reading articles.
* Paging the Article:: Scrolling the current article.
* Reply Followup and Post:: Posting articles.
+* Delayed Articles::
* Marking Articles:: Marking articles as read, expirable, etc.
* Limiting:: You can limit the summary buffer.
* Threading:: How threads are made.
* Tree Display:: A more visual display of threads.
* Mail Group Commands:: Some commands can only be used in mail groups.
* Various Summary Stuff:: What didn't fit anywhere else.
-* Exiting the Summary Buffer:: Returning to the Group buffer.
+* Exiting the Summary Buffer:: Returning to the Group buffer,
+ or reselecting the current group.
* Crosspost Handling:: How crossposted articles are dealt with.
* Duplicate Suppression:: An alternative when crosspost handling fails.
* Security:: Decrypt and Verify.
+* Mailing List:: Mailing list minor mode.
Summary Buffer Format
-* Summary Buffer Lines:: You can specify how summary lines should look.
-* To From Newsgroups:: How to not display your own name.
-* Summary Buffer Mode Line:: You can say how the mode line should look.
-* Summary Highlighting:: Making the summary buffer all pretty and nice.
+* Summary Buffer Lines:: You can specify how summary lines should look.
+* To From Newsgroups:: How to not display your own name.
+* Summary Buffer Mode Line:: You can say how the mode line should look.
+* Summary Highlighting:: Making the summary buffer all pretty and nice.
Choosing Articles
-* Choosing Commands:: Commands for choosing articles.
-* Choosing Variables:: Variables that influence these commands.
+* Choosing Commands:: Commands for choosing articles.
+* Choosing Variables:: Variables that influence these commands.
Reply, Followup and Post
-* Summary Mail Commands:: Sending mail.
-* Summary Post Commands:: Sending news.
-* Summary Message Commands:: Other Message-related commands.
-* Canceling and Superseding:: ``Whoops, I shouldn't have called him that.''
+* Summary Mail Commands:: Sending mail.
+* Summary Post Commands:: Sending news.
+* Summary Message Commands:: Other Message-related commands.
+* Canceling and Superseding::
+
+Marking Articles
+
+* Unread Articles:: Marks for unread articles.
+* Read Articles:: Marks for read articles.
+* Other Marks:: Marks that do not affect readedness.
+* Setting Marks::
+* Generic Marking Commands::
+* Setting Process Marks::
Marking Articles
-* Unread Articles:: Marks for unread articles.
-* Read Articles:: Marks for read articles.
-* Other Marks:: Marks that do not affect readedness.
-* Setting Marks:: How to set and remove marks.
-* Generic Marking Commands:: How to customize the marking.
-* Setting Process Marks:: How to mark articles for later processing.
+* Setting Marks:: How to set and remove marks.
+* Generic Marking Commands:: How to customize the marking.
+* Setting Process Marks:: How to mark articles for later processing.
Threading
-* Customizing Threading:: Variables you can change to affect the threading.
-* Thread Commands:: Thread based commands in the summary buffer.
+* Customizing Threading:: Variables you can change to affect the threading.
+* Thread Commands:: Thread based commands in the summary buffer.
Customizing Threading
-* Loose Threads:: How Gnus gathers loose threads into bigger threads.
-* Filling In Threads:: Making the threads displayed look fuller.
-* More Threading:: Even more variables for fiddling with threads.
-* Low-Level Threading:: You thought it was over... but you were wrong!
+* Loose Threads:: How Gnus gathers loose threads into bigger threads.
+* Filling In Threads:: Making the threads displayed look fuller.
+* More Threading:: Even more variables for fiddling with threads.
+* Low-Level Threading:: You thought it was over... but you were wrong!
Decoding Articles
-* Uuencoded Articles:: Uudecode articles.
-* Shell Archives:: Unshar articles.
-* PostScript Files:: Split PostScript.
-* Other Files:: Plain save and binhex.
-* Decoding Variables:: Variables for a happy decoding.
-* Viewing Files:: You want to look at the result of the decoding?
+* Uuencoded Articles:: Uudecode articles.
+* Shell Archives:: Unshar articles.
+* PostScript Files:: Split PostScript.
+* Other Files:: Plain save and binhex.
+* Decoding Variables:: Variables for a happy decoding.
+* Viewing Files:: You want to look at the result of the decoding?
Decoding Variables
-* Rule Variables:: Variables that say how a file is to be viewed.
-* Other Decode Variables:: Other decode variables.
-* Uuencoding and Posting:: Variables for customizing uuencoding.
+* Rule Variables:: Variables that say how a file is to be viewed.
+* Other Decode Variables:: Other decode variables.
+* Uuencoding and Posting:: Variables for customizing uuencoding.
Article Treatment
-* Article Highlighting:: You want to make the article look like fruit salad.
-* Article Fontisizing:: Making emphasized text look nice.
-* Article Hiding:: You also want to make certain info go away.
-* Article Washing:: Lots of way-neat functions to make life better.
-* Article Buttons:: Click on URLs, Message-IDs, addresses and the like.
-* Article Date:: Grumble, UT!
-* Article Signature:: What is a signature?
-* Article Miscellania:: Various other stuff.
+* Article Highlighting:: You want to make the article look like fruit salad.
+* Article Fontisizing:: Making emphasized text look nice.
+* Article Hiding:: You also want to make certain info go away.
+* Article Washing:: Lots of way-neat functions to make life better.
+* Article Buttons:: Click on URLs, Message-IDs, addresses and the like.
+* Article Date:: Grumble, UT!
+* Article Signature:: What is a signature?
+* Article Miscellania:: Various other stuff.
Alternative Approaches
Various Summary Stuff
-* Summary Group Information:: Information oriented commands.
-* Searching for Articles:: Multiple article commands.
-* Summary Generation Commands:: (Re)generating the summary buffer.
-* Really Various Summary Commands:: Those pesky non-conformant commands.
+* Summary Group Information:: Information oriented commands.
+* Searching for Articles:: Multiple article commands.
+* Summary Generation Commands::
+* Really Various Summary Commands:: Those pesky non-conformant commands.
Article Buffer
-* Hiding Headers:: Deciding what headers should be displayed.
-* Using MIME:: Pushing articles through @sc{mime} before reading them.
-* Customizing Articles:: Tailoring the look of the articles.
-* Article Keymap:: Keystrokes available in the article buffer.
-* Misc Article:: Other stuff.
+* Hiding Headers:: Deciding what headers should be displayed.
+* Using MIME:: Pushing articles through @sc{mime} before reading them.
+* Customizing Articles:: Tailoring the look of the articles.
+* Article Keymap:: Keystrokes available in the article buffer.
+* Misc Article:: Other stuff.
Composing Messages
-* Mail:: Mailing and replying.
-* Posting Server:: What server should you post via?
-* Mail and Post:: Mailing and posting at the same time.
-* Archived Messages:: Where Gnus stores the messages you've sent.
-* Posting Styles:: An easier way to specify who you are.
-* Drafts:: Postponing messages and rejected messages.
-* Rejected Articles:: What happens if the server doesn't like your article?
-* Using GPG:: How to use GPG and MML to sign and encrypt messages
+* Mail:: Mailing and replying.
+* Posting Server:: What server should you post via?
+* Mail and Post:: Mailing and posting at the same time.
+* Archived Messages:: Where Gnus stores the messages you've sent.
+* Posting Styles:: An easier way to specify who you are.
+* Drafts:: Postponing messages and rejected messages.
+* Rejected Articles:: What happens if the server doesn't like your article?
+* Using GPG:: How to use GPG and MML to sign and encrypt messages
Select Methods
-* Server Buffer:: Making and editing virtual servers.
-* Getting News:: Reading USENET news with Gnus.
-* Getting Mail:: Reading your personal mail with Gnus.
-* Browsing the Web:: Getting messages from a plethora of Web sources.
-* Other Sources:: Reading directories, files, SOUP packets.
-* Combined Groups:: Combining groups into one group.
-* Gnus Unplugged:: Reading news and mail offline.
+* Server Buffer:: Making and editing virtual servers.
+* Getting News:: Reading USENET news with Gnus.
+* Getting Mail:: Reading your personal mail with Gnus.
+* Browsing the Web:: Getting messages from a plethora of Web sources.
+* IMAP:: Using Gnus as a @sc{imap} client.
+* Other Sources:: Reading directories, files, SOUP packets.
+* Combined Groups:: Combining groups into one group.
+* Gnus Unplugged:: Reading news and mail offline.
Server Buffer
-* Server Buffer Format:: You can customize the look of this buffer.
-* Server Commands:: Commands to manipulate servers.
-* Example Methods:: Examples server specifications.
-* Creating a Virtual Server:: An example session.
-* Server Variables:: Which variables to set.
-* Servers and Methods:: You can use server names as select methods.
-* Unavailable Servers:: Some servers you try to contact may be down.
+* Server Buffer Format:: You can customize the look of this buffer.
+* Server Commands:: Commands to manipulate servers.
+* Example Methods:: Examples server specifications.
+* Creating a Virtual Server:: An example session.
+* Server Variables:: Which variables to set.
+* Servers and Methods:: You can use server names as select methods.
+* Unavailable Servers:: Some servers you try to contact may be down.
Getting News
-* NNTP:: Reading news from an @sc{nntp} server.
-* News Spool:: Reading news from the local spool.
+* NNTP:: Reading news from an @sc{nntp} server.
+* News Spool:: Reading news from the local spool.
+
+@sc{nntp}
+
+* Direct Functions:: Connecting directly to the server.
+* Indirect Functions:: Connecting indirectly to the server.
+* Common Variables:: Understood by several connection functions.
Getting Mail
-* Mail in a Newsreader:: Important introductory notes.
-* Getting Started Reading Mail:: A simple cookbook example.
-* Splitting Mail:: How to create mail groups.
-* Mail Sources:: How to tell Gnus where to get mail from.
-* Mail Backend Variables:: Variables for customizing mail handling.
-* Fancy Mail Splitting:: Gnus can do hairy splitting of incoming mail.
-* Group Mail Splitting:: Use group customize to drive mail splitting.
-* Incorporating Old Mail:: What about the old mail you have?
-* Expiring Mail:: Getting rid of unwanted mail.
-* Washing Mail:: Removing cruft from the mail you get.
-* Duplicates:: Dealing with duplicated mail.
-* Not Reading Mail:: Using mail backends for reading other files.
-* Choosing a Mail Backend:: Gnus can read a variety of mail formats.
+* Mail in a Newsreader:: Important introductory notes.
+* Getting Started Reading Mail:: A simple cookbook example.
+* Splitting Mail:: How to create mail groups.
+* Mail Sources:: How to tell Gnus where to get mail from.
+* Mail Back End Variables:: Variables for customizing mail handling.
+* Fancy Mail Splitting:: Gnus can do hairy splitting of incoming mail.
+* Group Mail Splitting:: Use group customize to drive mail splitting.
+* Incorporating Old Mail:: What about the old mail you have?
+* Expiring Mail:: Getting rid of unwanted mail.
+* Washing Mail:: Removing gruft from the mail you get.
+* Duplicates:: Dealing with duplicated mail.
+* Not Reading Mail:: Using mail back ends for reading other files.
+* Choosing a Mail Back End:: Gnus can read a variety of mail formats.
+* Archiving Mail:: How to backup your mail.
Mail Sources
-* Mail Source Specifiers:: How to specify what a mail source is.
-* Mail Source Customization:: Some variables that influence things.
-* Fetching Mail:: Using the mail source specifiers.
+* Mail Source Specifiers:: How to specify what a mail source is.
+* Mail Source Customization:: Some variables that influence things.
+* Fetching Mail:: Using the mail source specifiers.
-Choosing a Mail Backend
+Choosing a Mail Back End
* Unix Mail Box:: Using the (quite) standard Un*x mbox.
* Rmail Babyl:: Emacs programs use the rmail babyl format.
* Mail Spool:: Store your mail in a private spool?
-* MH Spool:: An mhspool-like backend.
+* MH Spool:: An mhspool-like back end.
* Mail Folders:: Having one file for each group.
-* Comparing Mail Backends:: An in-depth looks at pros and cons.
+* Comparing Mail Back Ends:: An in-depth looks at pros and cons.
Browsing the Web
-* Web Searches:: Creating groups from articles that match a string.
-* Slashdot:: Reading the Slashdot comments.
-* Ultimate:: The Ultimate Bulletin Board systems.
-* Web Archive:: Reading mailing list archived on web.
-* RSS:: Reading RDF site summary.
-* Customizing w3:: Doing stuff to Emacs/w3 from Gnus.
+* Web Searches:: Creating groups from articles that match a string.
+* Slashdot:: Reading the Slashdot comments.
+* Ultimate:: The Ultimate Bulletin Board systems.
+* Web Archive:: Reading mailing list archived on web.
+* RSS:: Reading RDF site summary.
+* Customizing w3:: Doing stuff to Emacs/w3 from Gnus.
+
+@sc{imap}
+
+* Splitting in IMAP:: Splitting mail with nnimap.
+* Editing IMAP ACLs:: Limiting/enabling other users access to a mailbox.
+* Expunging mailboxes:: Equivalent of a "compress mailbox" button.
Other Sources
-* Directory Groups:: You can read a directory as if it was a newsgroup.
-* Anything Groups:: Dired? Who needs dired?
-* Document Groups:: Single files can be the basis of a group.
-* SOUP:: Reading @sc{soup} packets ``offline''.
-* Mail-To-News Gateways:: Posting articles via mail-to-news gateways.
-* IMAP:: Using Gnus as a @sc{imap} client.
+* Directory Groups:: You can read a directory as if it was a newsgroup.
+* Anything Groups:: Dired? Who needs dired?
+* Document Groups:: Single files can be the basis of a group.
+* SOUP:: Reading @sc{soup} packets ``offline''.
+* Mail-To-News Gateways:: Posting articles via mail-to-news gateways.
Document Groups
SOUP
-* SOUP Commands:: Commands for creating and sending @sc{soup} packets
-* SOUP Groups:: A backend for reading @sc{soup} packets.
-* SOUP Replies:: How to enable @code{nnsoup} to take over mail and news.
-
-@sc{imap}
-
-* Splitting in IMAP:: Splitting mail with nnimap.
-* Editing IMAP ACLs:: Limiting/enabling other users access to a mailbox.
-* Expunging mailboxes:: Equivalent of a "compress mailbox" button.
+* SOUP Commands:: Commands for creating and sending @sc{soup} packets
+* SOUP Groups:: A back end for reading @sc{soup} packets.
+* SOUP Replies:: How to enable @code{nnsoup} to take over mail and news.
Combined Groups
-* Virtual Groups:: Combining articles from many groups.
-* Kibozed Groups:: Looking through parts of the newsfeed for articles.
+* Virtual Groups:: Combining articles from many groups.
+* Kibozed Groups:: Looking through parts of the newsfeed for articles.
Gnus Unplugged
-* Agent Basics:: How it all is supposed to work.
-* Agent Categories:: How to tell the Gnus Agent what to download.
-* Agent Commands:: New commands for all the buffers.
-* Agent Expiry:: How to make old articles go away.
-* Agent and IMAP:: How to use the Agent with IMAP.
-* Outgoing Messages:: What happens when you post/mail something?
-* Agent Variables:: Customizing is fun.
-* Example Setup:: An example @file{.gnus.el} file for offline people.
-* Batching Agents:: How to fetch news from a @code{cron} job.
-* Agent Caveats:: What you think it'll do and what it does.
+* Agent Basics:: How it all is supposed to work.
+* Agent Categories:: How to tell the Gnus Agent what to download.
+* Agent Commands:: New commands for all the buffers.
+* Agent Expiry:: How to make old articles go away.
+* Agent and IMAP:: How to use the Agent with IMAP.
+* Outgoing Messages:: What happens when you post/mail something?
+* Agent Variables:: Customizing is fun.
+* Example Setup:: An example @file{.gnus.el} file for offline people.
+* Batching Agents:: How to fetch news from a @code{cron} job.
+* Agent Caveats:: What you think it'll do and what it does.
Agent Categories
-* Category Syntax:: What a category looks like.
-* Category Buffer:: A buffer for maintaining categories.
-* Category Variables:: Customize'r'Us.
+* Category Syntax:: What a category looks like.
+* Category Buffer:: A buffer for maintaining categories.
+* Category Variables:: Customize'r'Us.
Agent Commands
Scoring
-* Summary Score Commands:: Adding score entries for the current group.
-* Group Score Commands:: General score commands.
-* Score Variables:: Customize your scoring. (My, what terminology).
-* Score File Format:: What a score file may contain.
-* Score File Editing:: You can edit score files by hand as well.
-* Adaptive Scoring:: Big Sister Gnus knows what you read.
-* Home Score File:: How to say where new score entries are to go.
-* Followups To Yourself:: Having Gnus notice when people answer you.
-* Scoring Tips:: How to score effectively.
-* Reverse Scoring:: That problem child of old is not problem.
-* Global Score Files:: Earth-spanning, ear-splitting score files.
-* Kill Files:: They are still here, but they can be ignored.
-* Converting Kill Files:: Translating kill files to score files.
-* GroupLens:: Getting predictions on what you like to read.
-* Advanced Scoring:: Using logical expressions to build score rules.
-* Score Decays:: It can be useful to let scores wither away.
+* Summary Score Commands:: Adding score entries for the current group.
+* Group Score Commands:: General score commands.
+* Score Variables:: Customize your scoring. (My, what terminology).
+* Score File Format:: What a score file may contain.
+* Score File Editing:: You can edit score files by hand as well.
+* Adaptive Scoring:: Big Sister Gnus knows what you read.
+* Home Score File:: How to say where new score entries are to go.
+* Followups To Yourself:: Having Gnus notice when people answer you.
+* Scoring On Other Headers:: Scoring on non-standard headers.
+* Scoring Tips:: How to score effectively.
+* Reverse Scoring:: That problem child of old is not problem.
+* Global Score Files:: Earth-spanning, ear-splitting score files.
+* Kill Files:: They are still here, but they can be ignored.
+* Converting Kill Files:: Translating kill files to score files.
+* GroupLens:: Getting predictions on what you like to read.
+* Advanced Scoring:: Using logical expressions to build score rules.
+* Score Decays:: It can be useful to let scores wither away.
GroupLens
-* Using GroupLens:: How to make Gnus use GroupLens.
-* Rating Articles:: Letting GroupLens know how you rate articles.
-* Displaying Predictions:: Displaying predictions given by GroupLens.
-* GroupLens Variables:: Customizing GroupLens.
+* Using GroupLens:: How to make Gnus use GroupLens.
+* Rating Articles:: Letting GroupLens know how you rate articles.
+* Displaying Predictions:: Displaying predictions given by GroupLens.
+* GroupLens Variables:: Customizing GroupLens.
Advanced Scoring
Various
-* Process/Prefix:: A convention used by many treatment commands.
-* Interactive:: Making Gnus ask you many questions.
-* Symbolic Prefixes:: How to supply some Gnus functions with options.
-* Formatting Variables:: You can specify what buffers should look like.
-* Windows Configuration:: Configuring the Gnus buffer windows.
-* Faces and Fonts:: How to change how faces look.
-* Compilation:: How to speed Gnus up.
-* Mode Lines:: Displaying information in the mode lines.
-* Highlighting and Menus:: Making buffers look all nice and cozy.
-* Buttons:: Get tendinitis in ten easy steps!
-* Daemons:: Gnus can do things behind your back.
-* NoCeM:: How to avoid spam and other fatty foods.
-* Undo:: Some actions can be undone.
-* Moderation:: What to do if you're a moderator.
-* XEmacs Enhancements:: There are more pictures and stuff under XEmacs.
-* Fuzzy Matching:: What's the big fuzz?
-* Thwarting Email Spam:: A how-to on avoiding unsolicited commercial email.
-* Various Various:: Things that are really various.
+* Process/Prefix:: A convention used by many treatment commands.
+* Interactive:: Making Gnus ask you many questions.
+* Symbolic Prefixes:: How to supply some Gnus functions with options.
+* Formatting Variables:: You can specify what buffers should look like.
+* Window Layout:: Configuring the Gnus buffer windows.
+* Faces and Fonts:: How to change how faces look.
+* Compilation:: How to speed Gnus up.
+* Mode Lines:: Displaying information in the mode lines.
+* Highlighting and Menus:: Making buffers look all nice and cozy.
+* Buttons:: Get tendinitis in ten easy steps!
+* Daemons:: Gnus can do things behind your back.
+* NoCeM:: How to avoid spam and other fatty foods.
+* Undo:: Some actions can be undone.
+* Moderation:: What to do if you're a moderator.
+* Image Enhancements:: There are more pictures and stuff under XEmacs.
+* Fuzzy Matching:: What's the big fuzz?
+* Thwarting Email Spam:: A how-to on avoiding unsolicited commercial email.
+* Various Various:: Things that are really various.
Formatting Variables
-* Formatting Basics:: A formatting variable is basically a format string.
-* Mode Line Formatting:: Some rules about mode line formatting variables.
-* Advanced Formatting:: Modifying output in various ways.
-* User-Defined Specs:: Having Gnus call your own functions.
-* Formatting Fonts:: Making the formatting look colorful and nice.
+* Formatting Basics:: A formatting variable is basically a format string.
+* Mode Line Formatting:: Some rules about mode line formatting variables.
+* Advanced Formatting:: Modifying output in various ways.
+* User-Defined Specs:: Having Gnus call your own functions.
+* Formatting Fonts:: Making the formatting look colorful and nice.
+* Positioning Point:: Moving point to a position after an operation.
+* Tabulation:: Tabulating your output.
+* Wide Characters:: Dealing with wide characters.
XEmacs Enhancements
-* Picons:: How to display pictures of what your reading.
-* Smileys:: Show all those happy faces the way they were meant to be shown.
-* Toolbar:: Click'n'drool.
-* XVarious:: Other XEmacsy Gnusey variables.
+* Picons:: How to display pictures of what your reading.
+* Smileys:: Show all those happy faces the way they were meant to be shown.
+* Toolbar:: Click'n'drool.
+* XVarious:: Other XEmacsy Gnusey variables.
Picons
-* Picon Basics:: What are picons and How do I get them.
-* Picon Requirements:: Don't go further if you aren't using XEmacs.
-* Easy Picons:: Displaying Picons---the easy way.
-* Hard Picons:: The way you should do it. You'll learn something.
-* Picon Useless Configuration:: Other variables you can trash/tweak/munge/play with.
+* Picon Basics:: What are picons and How do I get them.
+* Picon Requirements:: Don't go further if you aren't using XEmacs.
+* Easy Picons:: Displaying Picons---the easy way.
+* Hard Picons:: The way you should do it. You'll learn something.
+* Picon Useless Configuration:: Other variables you can trash/tweak/munge/play with.
Appendices
-* History:: How Gnus got where it is today.
-* On Writing Manuals:: Why this is not a beginner's guide.
-* Terminology:: We use really difficult, like, words here.
-* Customization:: Tailoring Gnus to your needs.
-* Troubleshooting:: What you might try if things do not work.
-* Gnus Reference Guide:: Rilly, rilly technical stuff.
-* Emacs for Heathens:: A short introduction to Emacsian terms.
-* Frequently Asked Questions:: A question-and-answer session.
+* History:: How Gnus got where it is today.
+* On Writing Manuals:: Why this is not a beginner's guide.
+* Terminology:: We use really difficult, like, words here.
+* Customization:: Tailoring Gnus to your needs.
+* Troubleshooting:: What you might try if things do not work.
+* Gnus Reference Guide:: Rilly, rilly technical stuff.
+* Emacs for Heathens:: A short introduction to Emacsian terms.
History
-* Gnus Versions:: What Gnus versions have been released.
-* Other Gnus Versions:: Other Gnus versions that also have been released.
-* Why?:: What's the point of Gnus?
-* Compatibility:: Just how compatible is Gnus with @sc{gnus}?
-* Conformity:: Gnus tries to conform to all standards.
-* Emacsen:: Gnus can be run on a few modern Emacsen.
-* Gnus Development:: How Gnus is developed.
-* Contributors:: Oodles of people.
-* New Features:: Pointers to some of the new stuff in Gnus.
+* Gnus Versions:: What Gnus versions have been released.
+* Other Gnus Versions:: Other Gnus versions that also have been released.
+* Why?:: What's the point of Gnus?
+* Compatibility:: Just how compatible is Gnus with @sc{gnus}?
+* Conformity:: Gnus tries to conform to all standards.
+* Emacsen:: Gnus can be run on a few modern Emacsen.
+* Gnus Development:: How Gnus is developed.
+* Contributors:: Oodles of people.
+* New Features:: Pointers to some of the new stuff in Gnus.
New Features
-* ding Gnus:: New things in Gnus 5.0/5.1, the first new Gnus.
-* September Gnus:: The Thing Formally Known As Gnus 5.2/5.3.
-* Red Gnus:: Third time best---Gnus 5.4/5.5.
-* Quassia Gnus:: Two times two is four, or Gnus 5.6/5.7.
-* Pterodactyl Gnus:: Pentad also starts with P, AKA Gnus 5.8/5.9.
+* ding Gnus:: New things in Gnus 5.0/5.1, the first new Gnus.
+* September Gnus:: The Thing Formally Known As Gnus 5.2/5.3.
+* Red Gnus:: Third time best---Gnus 5.4/5.5.
+* Quassia Gnus:: Two times two is four, or Gnus 5.6/5.7.
+* Pterodactyl Gnus:: Pentad also starts with P, AKA Gnus 5.8/5.9.
Customization
-* Slow/Expensive Connection:: You run a local Emacs and get the news elsewhere.
-* Slow Terminal Connection:: You run a remote Emacs.
-* Little Disk Space:: You feel that having large setup files is icky.
-* Slow Machine:: You feel like buying a faster machine.
+* Slow/Expensive Connection:: You run a local Emacs and get the news elsewhere.
+* Slow Terminal Connection:: You run a remote Emacs.
+* Little Disk Space:: You feel that having large setup files is icky.
+* Slow Machine:: You feel like buying a faster machine.
Gnus Reference Guide
-* Gnus Utility Functions:: Common functions and variable to use.
-* Backend Interface:: How Gnus communicates with the servers.
-* Score File Syntax:: A BNF definition of the score file standard.
-* Headers:: How Gnus stores headers internally.
-* Ranges:: A handy format for storing mucho numbers.
-* Group Info:: The group info format.
-* Extended Interactive:: Symbolic prefixes and stuff.
-* Emacs/XEmacs Code:: Gnus can be run under all modern Emacsen.
-* Various File Formats:: Formats of files that Gnus use.
-
-Backend Interface
-
-* Required Backend Functions:: Functions that must be implemented.
-* Optional Backend Functions:: Functions that need not be implemented.
-* Error Messaging:: How to get messages and report errors.
-* Writing New Backends:: Extending old backends.
-* Hooking New Backends Into Gnus:: What has to be done on the Gnus end.
-* Mail-like Backends:: Some tips on mail backends.
+* Gnus Utility Functions:: Common functions and variable to use.
+* Back End Interface:: How Gnus communicates with the servers.
+* Score File Syntax:: A BNF definition of the score file standard.
+* Headers:: How Gnus stores headers internally.
+* Ranges:: A handy format for storing mucho numbers.
+* Group Info:: The group info format.
+* Extended Interactive:: Symbolic prefixes and stuff.
+* Emacs/XEmacs Code:: Gnus can be run under all modern Emacsen.
+* Various File Formats:: Formats of files that Gnus use.
+
+Back End Interface
+
+* Required Back End Functions:: Functions that must be implemented.
+* Optional Back End Functions:: Functions that need not be implemented.
+* Error Messaging:: How to get messages and report errors.
+* Writing New Back Ends:: Extending old back ends.
+* Hooking New Back Ends Into Gnus:: What has to be done on the Gnus end.
+* Mail-like Back Ends:: Some tips on mail back ends.
Various File Formats
-* Active File Format:: Information on articles and groups available.
-* Newsgroups File Format:: Group descriptions.
+* Active File Format:: Information on articles and groups available.
+* Newsgroups File Format:: Group descriptions.
Emacs for Heathens
-* Keystrokes:: Entering text and executing commands.
-* Emacs Lisp:: The built-in Emacs programming language.
+* Keystrokes:: Entering text and executing commands.
+* Emacs Lisp:: The built-in Emacs programming language.
@end detailmenu
@end menu
terminology section (@pxref{Terminology}).
@menu
-* Finding the News:: Choosing a method for getting news.
-* The First Time:: What does Gnus do the first time you start it?
-* The Server is Down:: How can I read my mail then?
-* Slave Gnusae:: You can have more than one Gnus active at a time.
-* Fetching a Group:: Starting Gnus just to read a group.
-* New Groups:: What is Gnus supposed to do with new groups?
-* Startup Files:: Those pesky startup files---@file{.newsrc}.
-* Auto Save:: Recovering from a crash.
-* The Active File:: Reading the active file over a slow line Takes Time.
-* Changing Servers:: You may want to move from one server to another.
-* Startup Variables:: Other variables you might change.
+* Finding the News:: Choosing a method for getting news.
+* The First Time:: What does Gnus do the first time you start it?
+* The Server is Down:: How can I read my mail then?
+* Slave Gnusae:: You can have more than one Gnus active at a time.
+* Fetching a Group:: Starting Gnus just to read a group.
+* New Groups:: What is Gnus supposed to do with new groups?
+* Changing Servers:: You may want to move from one server to another.
+* Startup Files:: Those pesky startup files---@file{.newsrc}.
+* Auto Save:: Recovering from a crash.
+* The Active File:: Reading the active file over a slow line Takes Time.
+* Startup Variables:: Other variables you might change.
@end menu
@end lisp
If you can use a local spool, you probably should, as it will almost
-certainly be much faster.
+certainly be much faster. But do not use the local spool if your
+server is running Leafnode; in this case, use @code{(nntp "localhost")}.
@vindex gnus-nntpserver-file
@cindex NNTPSERVER
appear on these servers will be subscribed (or not) just as native
groups are.
-For instance, if you use the @code{nnmbox} backend to read your mail, you
-would typically set this variable to
+For instance, if you use the @code{nnmbox} back end to read your mail,
+you would typically set this variable to
@lisp
(setq gnus-secondary-select-methods '((nnmbox "")))
@code{nil}, you can always subscribe to the new groups just by pressing
@kbd{U} in the group buffer (@pxref{Group Maintenance}). This variable
is @code{ask-server} by default. If you set this variable to
-@code{always}, then Gnus will query the backends for new groups even
+@code{always}, then Gnus will query the back ends for new groups even
when you do the @kbd{g} command (@pxref{Scanning New Messages}).
@menu
-* Checking New Groups:: Determining what groups are new.
-* Subscription Methods:: What Gnus should do with new groups.
-* Filtering New Groups:: Making Gnus ignore certain new groups.
+* Checking New Groups:: Determining what groups are new.
+* Subscription Methods:: What Gnus should do with new groups.
+* Filtering New Groups:: Making Gnus ignore certain new groups.
@end menu
@item gnus-subscribe-topics
@vindex gnus-subscribe-topics
-Put the groups into the topic that has a matching @code{subscribe} topic
+Put the groups into the topic that has a matching @code{subscribe} topic
parameter (@pxref{Topic Parameters}). For instance, a @code{subscribe}
topic parameter that looks like
"nnslashdot"
@end example
-will mean that all groups that match that regex will be subscribed under
+will mean that all groups that match that regex will be subscribed under
that topic.
If no topics match the groups, the groups will be subscribed in the
thought it would be nice to have two of these. This variable is more
meant for setting some ground rules, while the other variable is used
more for user fiddling. By default this variable makes all new groups
-that come from mail backends (@code{nnml}, @code{nnbabyl},
+that come from mail back ends (@code{nnml}, @code{nnbabyl},
@code{nnfolder}, @code{nnmbox}, and @code{nnmh}) subscribed. If you
don't like that, just set this variable to @code{nil}.
@code{LIST ACTIVE group} command, this isn't very nice to the server.
If you think that starting up Gnus takes too long, try all the three
-different values for this variable and see what works best for you.
+different values for this variable and see what works best for you.
In any case, if you use @code{some} or @code{nil}, you should definitely
kill all groups that you aren't interested in to speed things up.
@chapter Group Buffer
@cindex group buffer
+@c Alex Schroeder suggests to rearrange this as follows:
+@c
+@c <kensanata> ok, just save it for reference. I'll go to bed in a minute.
+@c 1. Selecting a Group, 2. (new) Finding a Group, 3. Group Levels,
+@c 4. Subscription Commands, 5. Group Maneuvering, 6. Group Data,
+@c 7. Group Score, 8. Group Buffer Format
+@c <kensanata> Group Levels should have more information on levels 5 to 9. I
+@c suggest to split the 4th paragraph ("Gnus considers groups...") as follows:
+@c <kensanata> First, "Gnus considers groups... (default 9)."
+@c <kensanata> New, a table summarizing what levels 1 to 9 mean.
+@c <kensanata> Third, "Gnus treats subscribed ... reasons of efficiency"
+@c <kensanata> Then expand the next paragraph or add some more to it.
+@c This short one sentence explains levels 1 and 2, therefore I understand
+@c that I should keep important news at 3 and boring news at 4.
+@c Say so! Then go on to explain why I should bother with levels 6 to 9.
+@c Maybe keep those that you don't want to read temporarily at 6,
+@c those that you never want to read at 8, those that offend your
+@c human rights at 9...
+
+
The @dfn{group buffer} lists all (or parts) of the available groups. It
is the first buffer shown when Gnus starts, and will never be killed as
long as Gnus is active.
@iftex
@iflatex
\gnusfigure{The Group Buffer}{320}{
-\put(75,50){\epsfig{figure=tmp/group.ps,height=9cm}}
+\put(75,50){\epsfig{figure=ps/group,height=9cm}}
\put(120,37){\makebox(0,0)[t]{Buffer name}}
\put(120,38){\vector(1,2){10}}
\put(40,60){\makebox(0,0)[r]{Mode line}}
@end iftex
@menu
-* Group Buffer Format:: Information listed and how you can change it.
-* Group Maneuvering:: Commands for moving in the group buffer.
-* Selecting a Group:: Actually reading news.
-* Group Data:: Changing the info for a group.
-* Subscription Commands:: Unsubscribing, killing, subscribing.
-* Group Levels:: Levels? What are those, then?
-* Group Score:: A mechanism for finding out what groups you like.
-* Marking Groups:: You can mark groups for later processing.
-* Foreign Groups:: Creating and editing groups.
-* Group Parameters:: Each group may have different parameters set.
-* Listing Groups:: Gnus can list various subsets of the groups.
-* Sorting Groups:: Re-arrange the group order.
-* Group Maintenance:: Maintaining a tidy @file{.newsrc} file.
-* Browse Foreign Server:: You can browse a server. See what it has to offer.
-* Exiting Gnus:: Stop reading news and get some work done.
-* Group Topics:: A folding group mode divided into topics.
-* Misc Group Stuff:: Other stuff that you can to do.
+* Group Buffer Format:: Information listed and how you can change it.
+* Group Maneuvering:: Commands for moving in the group buffer.
+* Selecting a Group:: Actually reading news.
+* Subscription Commands:: Unsubscribing, killing, subscribing.
+* Group Data:: Changing the info for a group.
+* Group Levels:: Levels? What are those, then?
+* Group Score:: A mechanism for finding out what groups you like.
+* Marking Groups:: You can mark groups for later processing.
+* Foreign Groups:: Creating and editing groups.
+* Group Parameters:: Each group may have different parameters set.
+* Listing Groups:: Gnus can list various subsets of the groups.
+* Sorting Groups:: Re-arrange the group order.
+* Group Maintenance:: Maintaining a tidy @file{.newsrc} file.
+* Browse Foreign Server:: You can browse a server. See what it has to offer.
+* Exiting Gnus:: Stop reading news and get some work done.
+* Group Topics:: A folding group mode divided into topics.
+* Misc Group Stuff:: Other stuff that you can to do.
@end menu
@section Group Buffer Format
@menu
-* Group Line Specification:: Deciding how the group buffer is to look.
-* Group Modeline Specification:: The group buffer modeline.
-* Group Highlighting:: Having nice colors in the group buffer.
+* Group Line Specification:: Deciding how the group buffer is to look.
+* Group Modeline Specification:: The group buffer modeline.
+* Group Highlighting:: Having nice colors in the group buffer.
@end menu
@samp{%M%S%5y: %(%g%)\n} is the value that produced those lines above.
There should always be a colon on the line; the cursor always moves to
-the colon after performing an operation. Nothing else is required---not
-even the group name. All displayed text is just window dressing, and is
-never examined by Gnus. Gnus stores all real information it needs using
-text properties.
+the colon after performing an operation. @xref{Positioning
+Point}. Nothing else is required---not even the group name. All
+displayed text is just window dressing, and is never examined by Gnus.
+Gnus stores all real information it needs using text properties.
(Note that if you make a really strange, wonderful, spreadsheet-like
layout, everybody will believe you are hard at work with the accounting
Estimated total number of articles. (This is really @var{max-number}
minus @var{min-number} plus 1.)
+Gnus uses this estimation because the NNTP protocol provides efficient
+access to @var{max-number} and @var{min-number} but getting the true
+unread message count is not possible efficiently. For hysterical
+raisins, even the mail back ends, where the true number of unread
+messages might be available efficiently, use the same limited
+interface. To remove this restriction from Gnus means that the
+back end interface has to be changed, which is not an easy job. If you
+want to work on this, please contact the Gnus mailing list.
+
@item y
Number of unread, unticked, non-dormant articles.
command, but this one does it without expunging and hiding dormants
(@code{gnus-group-visible-select-group}).
-@item M-C-RET
-@kindex M-C-RET (Group)
+@item C-M-RET
+@kindex C-M-RET (Group)
@findex gnus-group-select-group-ephemerally
Finally, this command selects the current group ephemerally without
doing any processing of its contents
@vindex gnus-select-group-hook
@vindex gnus-auto-select-first
-@code{gnus-auto-select-first} control whether any articles are selected
+If @code{gnus-auto-select-first} is non-@code{nil}, select an article
automatically when entering a group with the @kbd{SPACE} command.
+Which article this is is controlled by the
+@code{gnus-auto-select-subject} variable. Valid values for this
+variable is:
@table @code
-@item nil
-Don't select any articles when entering the group. Just display the
-full summary buffer.
-
-@item t
-Select the first unread article when entering the group.
-
-@item best
-Select the highest scored article in the group when entering the
-group.
-
-@end table
+@item unread
+Place point on the subject line of the first unread article.
-This variable can also be a function. In that case, that function will
-be called to place point on a subject line, and/or select some article.
-Useful functions include:
+@item first
+Place point on the subject line of the first article.
-@table @code
-@item gnus-summary-first-unread-subject
-Place point on the subject line of the first unread article, but
-don't select the article.
+@item unseen
+Place point on the subject line of the first unseen article.
-@item gnus-summary-first-unread-article
-Select the first unread article.
+@item best
+Place point on the subject line of the highest-scored unread article.
-@item gnus-summary-best-unread-article
-Select the highest-scored unread article.
@end table
+This variable can also be a function. In that case, that function
+will be called to place point on a subject line.
If you want to prevent automatic selection in some group (say, in a
-binary group with Huge articles) you can set this variable to @code{nil}
-in @code{gnus-select-group-hook}, which is called when a group is
+binary group with Huge articles) you can set the
+@code{gnus-auto-select-first} variable to @code{nil} in
+@code{gnus-select-group-hook}, which is called when a group is
selected.
Rename the current group to something else
(@code{gnus-group-rename-group}). This is valid only on some
groups---mail groups mostly. This command might very well be quite slow
-on some backends.
+on some back ends.
@item G c
@kindex G c (Group)
@findex gnus-group-enter-directory
@cindex nneething
Read an arbitrary directory as if it were a newsgroup with the
-@code{nneething} backend (@code{gnus-group-enter-directory}).
+@code{nneething} back end (@code{gnus-group-enter-directory}).
@xref{Anything Groups}.
@item G f
Make a group based on some file or other
(@code{gnus-group-make-doc-group}). If you give a prefix to this
command, you will be prompted for a file name and a file type.
-Currently supported types are @code{babyl}, @code{mbox}, @code{digest},
-@code{mmdf}, @code{news}, @code{rnews}, @code{clari-briefs},
-@code{rfc934}, @code{rfc822-forward}, @code{nsmail} and @code{forward}.
-If you run this command without a prefix, Gnus will guess at the file
+Currently supported types are @code{mbox}, @code{babyl},
+@code{digest}, @code{news}, @code{rnews}, @code{mmdf}, @code{forward},
+@code{rfc934}, @code{rfc822-forward}, @code{mime-parts},
+@code{standard-digest}, @code{slack-digest}, @code{clari-briefs},
+@code{nsmail}, @code{outlook}, @code{oe-dbx}, and @code{mailman}. If
+you run this command without a prefix, Gnus will guess at the file
type. @xref{Document Groups}.
@item G u
@code{to-list} group parameter, one will be added automatically upon
sending the message.
+@findex gnus-mailing-list-mode
+@cindex Mail List Groups
+If this variable is set, @code{gnus-mailing-list-mode} is turned on when
+entering summary buffer.
+
See also @code{gnus-parameter-to-list-alist}.
@item visible
All adaptive score entries will be put into this file.
@item admin-address
+@cindex admin-address
When unsubscribing from a mailing list you should never send the
unsubscription notice to the mailing list itself. Instead, you'd send
messages to the administrative address. This parameter allows you to
put the admin address somewhere convenient.
@item display
+@cindex display
Elements that look like @code{(display . MODE)} say which articles to
display on entering the group. Valid values are:
@item all
Display all articles, both read and unread.
+@item an integer
+Display the last INTEGER articles in the group. This is the same as
+entering the group with C-u INTEGER.
+
@item default
Display the default visible articles, which normally includes unread and
ticked articles.
+
+@item an array
+Display articles that satisfy a predicate.
+
+Here are some examples:
+
+@table @code
+@item [read]
+Display only read articles.
+
+@item [not expire]
+Display everything except expirable articles.
+
+@item [and (not reply) (not expire)]
+Display everything except expirable and articles you've already
+responded to.
+@end table
+
+The available operators are @code{not}, @code{and} and @code{or}.
+Predicates include @code{tick}, @code{unsend}, @code{undownload},
+@code{read}, @code{dormant}, @code{expire}, @code{reply},
+@code{killed}, @code{bookmark}, @code{score}, @code{save},
+@code{cache}, @code{forward}, @code{seen} and @code{recent}.
+
@end table
+The @code{display} parameter works by limiting the summary buffer to
+the subset specified. You can pop the limit by using the @kbd{/ w}
+command (@pxref{Limiting}).
+
@item comment
+@cindex comment
Elements that look like @code{(comment . "This is a comment")}
are arbitrary comments on the group. They are currently ignored by
Gnus, but provide a place for you to store information on particular
groups.
@item charset
+@cindex charset
Elements that look like @code{(charset . iso-8859-1)} will make
@code{iso-8859-1} the default charset; that is, the charset that will be
used for all articles that do not specify a charset.
See also @code{gnus-group-charset-alist}.
@item ignored-charsets
-Elements that look like @code{(ignored-charsets x-known iso-8859-1)}
+@cindex ignored-charset
+Elements that look like @code{(ignored-charsets x-unknown iso-8859-1)}
will make @code{iso-8859-1} and @code{x-unknown} ignored; that is, the
default charset will be used for decoding articles.
See also @code{gnus-group-ignored-charsets-alist}.
@item posting-style
+@cindex posting-style
You can store additional posting style information for this group only
here (@pxref{Posting Styles}). The format is that of an entry in the
@code{gnus-posting-styles} alist, except that there's no regexp matching
(signature "Funky Signature"))
@end example
+@item post-method
+@cindex post-method
+If it is set, the value is used as the method for posting message
+instead of @code{gnus-post-method}.
+
@item banner
+@cindex banner
An item like @code{(banner . "regex")} causes any part of an article
that matches the regular expression "regex" to be stripped. Instead of
"regex", you can also use the symbol @code{signature} which strips the
last signature or any of the elements of the alist
@code{gnus-article-banner-alist}.
+@item sieve
+@cindex sieve
+This parameter contains a Sieve test that should match incoming mail
+that should be placed in this group. From this group parameter, a
+Sieve @samp{IF} control structure is generated, having the test as the
+condition and @samp{fileinto "group.name";} as the body.
+
+For example, if the INBOX.list.sieve group has the @code{(sieve
+address "sender" "sieve-admin@@extundo.com")} group parameter, when
+translating the group parameter into a Sieve script (@pxref{Sieve
+Commands}) the following Sieve code is generated:
+
+@example
+ if address \"sender\" \"sieve-admin@@extundo.com\" @{
+ fileinto \"INBOX.list.sieve\";
+ @}
+@end example
+
+The Sieve language is described in RFC 3028. @xref{Top, , Top, sieve,
+Emacs Sieve}.
+
@item (@var{variable} @var{form})
You can use the group parameters to set variables local to the group you
are entering. If you want to turn threading off in @samp{news.answers},
silly Lisp errors.) You might also be interested in reading about topic
parameters (@pxref{Topic Parameters}).
+Group parameters can be set via the @code{gnus-parameters} variable too.
+But some variables, such as @code{visible}, have no effect. For
+example:
+
+@example
+(setq gnus-parameters
+ '(("mail\\..*"
+ (gnus-show-threads nil)
+ (gnus-use-scoring nil)
+ (gnus-summary-line-format
+ "%U%R%z%I%(%[%d:%ub%-23,23f%]%) %s\n")
+ (gcc-self . t)
+ (display . all))
+
+ ("^nnimap:\\(foo.bar\\)$"
+ (to-group . "\\1"))
+
+ ("mail\\.me"
+ (gnus-use-scoring t))
+
+ ("list\\..*"
+ (total-expire . t)
+ (broken-reply-to . t))))
+@end example
+
+String value of parameters will be subjected to regexp substitution, as
+the @code{to-group} example shows.
+
@node Listing Groups
@section Listing Groups
@item G S m
@kindex G S m (Group)
@findex gnus-group-sort-groups-by-method
-Sort the group buffer alphabetically by backend name
+Sort the group buffer alphabetically by back end name
(@code{gnus-group-sort-groups-by-method}).
@end table
@item G P m
@kindex G P m (Group)
@findex gnus-group-sort-selected-groups-by-method
-Sort the groups alphabetically by backend name
+Sort the groups alphabetically by back end name
(@code{gnus-group-sort-selected-groups-by-method}).
@end table
@kindex C-c C-x (Group)
@findex gnus-group-expire-articles
Run all expirable articles in the current group through the expiry
-process (if any) (@code{gnus-group-expire-articles}).
+process (if any) (@code{gnus-group-expire-articles}). That is, delete
+all expirable articles in the group that have been around for a while.
+(@pxref{Expiring Mail}).
-@item C-c M-C-x
-@kindex C-c M-C-x (Group)
+@item C-c C-M-x
+@kindex C-c C-M-x (Group)
@findex gnus-group-expire-all-groups
-Run all articles in all groups through the expiry process
+Run all expirable articles in all groups through the expiry process
(@code{gnus-group-expire-all-groups}).
@end table
@iftex
@iflatex
\gnusfigure{Group Topics}{400}{
-\put(75,50){\epsfig{figure=tmp/group-topic.ps,height=9cm}}
+\put(75,50){\epsfig{figure=ps/group-topic,height=9cm}}
}
@end iflatex
@end iftex
is a toggling command.)
Go ahead, just try it. I'll still be here when you get back. La de
-dum... Nice tune, that... la la la... What, you're back? Yes, and now
-press @kbd{l}. There. All your groups are now listed under
+dum... Nice tune, that... la la la... What, you're back? Yes, and
+now press @kbd{l}. There. All your groups are now listed under
@samp{misc}. Doesn't that make you feel all warm and fuzzy? Hot and
bothered?
If you want this permanently enabled, you should add that minor mode to
-the hook for the group mode:
+the hook for the group mode. Put the following line in your
+@file{~/.gnus} file:
@lisp
(add-hook 'gnus-group-mode-hook 'gnus-topic-mode)
@end lisp
@menu
-* Topic Variables:: How to customize the topics the Lisp Way.
-* Topic Commands:: Interactive E-Z commands.
-* Topic Sorting:: Sorting each topic individually.
-* Topic Topology:: A map of the world.
-* Topic Parameters:: Parameters that apply to all groups in a topic.
+* Topic Commands:: Interactive E-Z commands.
+* Topic Variables:: How to customize the topics the Lisp Way.
+* Topic Sorting:: Sorting each topic individually.
+* Topic Topology:: A map of the world.
+* Topic Parameters:: Parameters that apply to all groups in a topic.
@end menu
-@node Topic Variables
-@subsection Topic Variables
-@cindex topic variables
-
-Now, if you select a topic, it will fold/unfold that topic, which is
-really neat, I think.
-
-@vindex gnus-topic-line-format
-The topic lines themselves are created according to the
-@code{gnus-topic-line-format} variable (@pxref{Formatting Variables}).
-Valid elements are:
-
-@table @samp
-@item i
-Indentation.
-@item n
-Topic name.
-@item v
-Visibility.
-@item l
-Level.
-@item g
-Number of groups in the topic.
-@item a
-Number of unread articles in the topic.
-@item A
-Number of unread articles in the topic and all its subtopics.
-@end table
-
-@vindex gnus-topic-indent-level
-Each sub-topic (and the groups in the sub-topics) will be indented with
-@code{gnus-topic-indent-level} times the topic level number of spaces.
-The default is 2.
-
-@vindex gnus-topic-mode-hook
-@code{gnus-topic-mode-hook} is called in topic minor mode buffers.
-
-@vindex gnus-topic-display-empty-topics
-The @code{gnus-topic-display-empty-topics} says whether to display even
-topics that have no unread articles in them. The default is @code{t}.
-
-
@node Topic Commands
@subsection Topic Commands
@cindex topic commands
available. In addition, a few of the standard keys change their
definitions slightly.
+In general, the following kinds of operations are possible on topics.
+First of all, you want to create topics. Secondly, you want to put
+groups in topics and to move them around until you have an order you
+like. The third kind of operation is to show/hide parts of the whole
+shebang. You might want to hide a topic including its subtopics and
+groups, to get a better overview of the other groups.
+
+Here is a list of the basic keys that you might need to set up topics
+the way you like.
+
@table @kbd
@item T n
Prompt for a new topic name and create it
(@code{gnus-topic-create-topic}).
+@item T TAB
+@itemx TAB
+@kindex T TAB (Topic)
+@kindex TAB (Topic)
+@findex gnus-topic-indent
+``Indent'' the current topic so that it becomes a sub-topic of the
+previous topic (@code{gnus-topic-indent}). If given a prefix,
+``un-indent'' the topic instead.
+
+@item M-TAB
+@kindex M-TAB (Topic)
+@findex gnus-topic-unindent
+``Un-indent'' the current topic so that it becomes a sub-topic of the
+parent of its current parent (@code{gnus-topic-unindent}).
+
+@end table
+
+The following two keys can be used to move groups and topics around.
+They work like the well-known cut and paste. @kbd{C-k} is like cut and
+@kbd{C-y} is like paste. Of course, this being Emacs, we use the terms
+kill and yank rather than cut and paste.
+
+@table @kbd
+
+@item C-k
+@kindex C-k (Topic)
+@findex gnus-topic-kill-group
+Kill a group or topic (@code{gnus-topic-kill-group}). All groups in the
+topic will be removed along with the topic.
+
+@item C-y
+@kindex C-y (Topic)
+@findex gnus-topic-yank-group
+Yank the previously killed group or topic
+(@code{gnus-topic-yank-group}). Note that all topics will be yanked
+before all groups.
+
+So, to move a topic to the beginning of the list of topics, just hit
+@kbd{C-k} on it. This is like the `cut' part of cut and paste. Then,
+move the cursor to the beginning of the buffer (just below the `Gnus'
+topic) and hit @kbd{C-y}. This is like the `paste' part of cut and
+paste. Like I said -- E-Z.
+
+You can use @kbd{C-k} and @kbd{C-y} on groups as well as on topics. So
+you can move topics around as well as groups.
+
+@end table
+
+After setting up the topics the way you like them, you might wish to
+hide a topic, or to show it again. That's why we have the following
+key.
+
+@table @kbd
+
+@item RET
+@kindex RET (Topic)
+@findex gnus-topic-select-group
+@itemx SPACE
+Either select a group or fold a topic (@code{gnus-topic-select-group}).
+When you perform this command on a group, you'll enter the group, as
+usual. When done on a topic line, the topic will be folded (if it was
+visible) or unfolded (if it was folded already). So it's basically a
+toggling command on topics. In addition, if you give a numerical
+prefix, group on that level (and lower) will be displayed.
+
+@end table
+
+Now for a list of other commands, in no particular order.
+
+@table @kbd
+
@item T m
@kindex T m (Topic)
@findex gnus-topic-move-group
@item T j
@kindex T j (Topic)
@findex gnus-topic-jump-to-topic
-Go to a topic (@code{gnus-topic-jump-to-topic}).
+Go to a topic (@code{gnus-topic-jump-to-topic}).
@item T c
@kindex T c (Topic)
Remove the process mark from all groups in the current topic
(@code{gnus-topic-unmark-topic}).
-@item T TAB
-@itemx TAB
-@kindex T TAB (Topic)
-@kindex TAB (Topic)
-@findex gnus-topic-indent
-``Indent'' the current topic so that it becomes a sub-topic of the
-previous topic (@code{gnus-topic-indent}). If given a prefix,
-``un-indent'' the topic instead.
-
-@item M-TAB
-@kindex M-TAB (Topic)
-@findex gnus-topic-unindent
-``Un-indent'' the current topic so that it becomes a sub-topic of the
-parent of its current parent (@code{gnus-topic-unindent}).
-
-@item RET
-@kindex RET (Topic)
-@findex gnus-topic-select-group
-@itemx SPACE
-Either select a group or fold a topic (@code{gnus-topic-select-group}).
-When you perform this command on a group, you'll enter the group, as
-usual. When done on a topic line, the topic will be folded (if it was
-visible) or unfolded (if it was folded already). So it's basically a
-toggling command on topics. In addition, if you give a numerical
-prefix, group on that level (and lower) will be displayed.
-
@item C-c C-x
@kindex C-c C-x (Topic)
@findex gnus-topic-expire-articles
-Run all expirable articles in the current group or topic through the expiry
-process (if any) (@code{gnus-topic-expire-articles}).
-
-@item C-k
-@kindex C-k (Topic)
-@findex gnus-topic-kill-group
-Kill a group or topic (@code{gnus-topic-kill-group}). All groups in the
-topic will be removed along with the topic.
-
-@item C-y
-@kindex C-y (Topic)
-@findex gnus-topic-yank-group
-Yank the previously killed group or topic
-(@code{gnus-topic-yank-group}). Note that all topics will be yanked
-before all groups.
+Run all expirable articles in the current group or topic through the
+expiry process (if any)
+(@code{gnus-topic-expire-articles}). (@pxref{Expiring Mail}).
@item T r
@kindex T r (Topic)
@end table
+@node Topic Variables
+@subsection Topic Variables
+@cindex topic variables
+
+The previous section told you how to tell Gnus which topics to display.
+This section explains how to tell Gnus what to display about each topic.
+
+@vindex gnus-topic-line-format
+The topic lines themselves are created according to the
+@code{gnus-topic-line-format} variable (@pxref{Formatting Variables}).
+Valid elements are:
+
+@table @samp
+@item i
+Indentation.
+@item n
+Topic name.
+@item v
+Visibility.
+@item l
+Level.
+@item g
+Number of groups in the topic.
+@item a
+Number of unread articles in the topic.
+@item A
+Number of unread articles in the topic and all its subtopics.
+@end table
+
+@vindex gnus-topic-indent-level
+Each sub-topic (and the groups in the sub-topics) will be indented with
+@code{gnus-topic-indent-level} times the topic level number of spaces.
+The default is 2.
+
+@vindex gnus-topic-mode-hook
+@code{gnus-topic-mode-hook} is called in topic minor mode buffers.
+
+@vindex gnus-topic-display-empty-topics
+The @code{gnus-topic-display-empty-topics} says whether to display even
+topics that have no unread articles in them. The default is @code{t}.
+
+
@node Topic Sorting
@subsection Topic Sorting
@cindex topic sorting
@item T S m
@kindex T S m (Topic)
@findex gnus-topic-sort-groups-by-method
-Sort the current topic alphabetically by backend name
+Sort the current topic alphabetically by back end name
(@code{gnus-topic-sort-groups-by-method}).
+@item T S e
+@kindex T S e (Topic)
+@findex gnus-topic-sort-groups-by-server
+Sort the current topic alphabetically by server name
+(@code{gnus-topic-sort-groups-by-server}).
+
@end table
@xref{Sorting Groups}, for more information about group sorting.
@table @code
@item subscribe
-When subscribing new groups by topic (@pxref{Subscription Methods}), the
-@code{subscribe} topic parameter says what groups go in what topic. Its
+When subscribing new groups by topic (@pxref{Subscription Methods}), the
+@code{subscribe} topic parameter says what groups go in what topic. Its
value should be a regexp to match the groups that should go in that
-topic.
+topic.
+
+@item subscribe-level
+When subscribing new groups by topic (see the @code{subscribe} parameter),
+the group will be subscribed with the level specified in the
+@code{subscribe-level} instead of @code{gnus-level-default-subscribed}.
@end table
@section Misc Group Stuff
@menu
-* Scanning New Messages:: Asking Gnus to see whether new messages have arrived.
-* Group Information:: Information and help on groups and Gnus.
-* Group Timestamp:: Making Gnus keep track of when you last read a group.
-* File Commands:: Reading and writing the Gnus files.
+* Scanning New Messages:: Asking Gnus to see whether new messages have arrived.
+* Group Information:: Information and help on groups and Gnus.
+* Group Timestamp:: Making Gnus keep track of when you last read a group.
+* File Commands:: Reading and writing the Gnus files.
+* Sieve Commands:: Managing Sieve scripts.
@end menu
@table @kbd
@item a
@kindex a (Group)
@findex gnus-group-post-news
-Post an article to a group (@code{gnus-group-post-news}). If given a
-prefix, the current group name will be used as the default.
+Start composing a message (a news by default)
+(@code{gnus-group-post-news}). If given a prefix, post to the group
+under the point. If the prefix is 1, prompt for a group to post to.
+Contrary to what the name of this function suggests, the prepared
+article might be a mail instead of a news, if a mail group is specified
+with the prefix argument. @xref{Composing Messages}.
@item m
@kindex m (Group)
@findex gnus-group-mail
-Mail a message somewhere (@code{gnus-group-mail}).
+Mail a message somewhere (@code{gnus-group-mail}). If given a prefix,
+use the posting style of the group under the point. If the prefix is 1,
+prompt for a group name to find the posting style.
+@xref{Composing Messages}.
+
+@item i
+@kindex i (Group)
+@findex gnus-group-news
+Start composing a news (@code{gnus-group-news}). If given a prefix,
+post to the group under the point. If the prefix is 1, prompt
+for group to post to. @xref{Composing Messages}.
+
+This function actually prepares a news even when using mail groups.
+This is useful for "posting" messages to mail groups without actually
+sending them over the network: they're just saved directly to the group
+in question. The corresponding back end must have a request-post method
+for this to work though.
@end table
@end lisp
@item gnus-group-name-charset-group-alist
+@cindex UTF-8 group names
@vindex gnus-group-name-charset-group-alist
-An alist of regexp of group name and the charset for group names.
-It is used to show non-ASCII group names.
+An alist of regexp of group name and the charset for group names. It
+is used to show non-ASCII group names. @code{((".*" utf-8))} is the
+default value if UTF-8 is supported, otherwise the default is nil.
For example:
@lisp
this command will check only groups of level @var{arg} and lower
(@code{gnus-group-get-new-news}). If given a non-numerical prefix, this
command will force a total re-reading of the active file(s) from the
-backend(s).
+back end(s).
@item M-g
@kindex M-g (Group)
@end table
-@node Summary Buffer
+@node Sieve Commands
+@subsection Sieve Commands
+@cindex group sieve commands
+
+Sieve is a server-side mail filtering language. In Gnus you can use
+the @code{sieve} group parameter (@pxref{Group Parameters}) to specify
+sieve rules that should apply to each group. Gnus provides two
+commands to translate all these group parameters into a proper Sieve
+script that can be transfered to the server somehow.
+
+@vindex gnus-sieve-file
+@vindex gnus-sieve-region-start
+@vindex gnus-sieve-region-end
+The generated Sieve script is placed in @code{gnus-sieve-file} (by
+default @file{~/.sieve}). The Sieve code that Gnus generate is placed
+between two delimiters, @code{gnus-sieve-region-start} and
+@code{gnus-sieve-region-end}, so you may write additional Sieve code
+outside these delimiters that will not be removed the next time you
+regenerate the Sieve script.
+
+@vindex gnus-sieve-crosspost
+The variable @code{gnus-sieve-crosspost} controls how the Sieve script
+is generated. If it is non-nil (the default) articles is placed in
+all groups that have matching rules, otherwise the article is only
+placed in the group with the first matching rule. For example, the
+group parameter @samp{(sieve address "sender"
+"owner-ding@@hpc.uh.edu")} will generate the following piece of Sieve
+code if @code{gnus-sieve-crosspost} is nil. (When
+@code{gnus-sieve-crosspost} is non-nil, it looks the same except that
+the line containing the call to @code{stop} is removed.)
+
+@example
+if address "sender" "owner-ding@@hpc.uh.edu" @{
+ fileinto "INBOX.ding";
+ stop;
+@}
+@end example
+
+@xref{Top, ,Top, sieve, Emacs Sieve}.
+
+@table @kbd
+
+@item D g
+@kindex D g (Group)
+@findex gnus-sieve-generate
+@vindex gnus-sieve-file
+@cindex generating sieve script
+Regenerate a Sieve script from the @code{sieve} group parameters and
+put you into the @code{gnus-sieve-file} without saving it.
+
+@item D u
+@kindex D u (Group)
+@findex gnus-sieve-update
+@vindex gnus-sieve-file
+@cindex updating sieve script
+Regenerates the Gnus managed part of @code{gnus-sieve-file} using the
+@code{sieve} group parameters, save the file and upload it to the
+server using the @code{sieveshell} program.
+
+@end table
+
+
+@node Summary Buffer
@chapter Summary Buffer
@cindex summary buffer
* Choosing Articles:: Reading articles.
* Paging the Article:: Scrolling the current article.
* Reply Followup and Post:: Posting articles.
+* Delayed Articles::
* Marking Articles:: Marking articles as read, expirable, etc.
* Limiting:: You can limit the summary buffer.
* Threading:: How threads are made.
* Crosspost Handling:: How crossposted articles are dealt with.
* Duplicate Suppression:: An alternative when crosspost handling fails.
* Security:: Decrypt and Verify.
+* Mailing List:: Mailing list minor mode.
@end menu
@iftex
@iflatex
\gnusfigure{The Summary Buffer}{180}{
-\put(0,0){\epsfig{figure=tmp/summary.ps,width=7.5cm}}
-\put(445,0){\makebox(0,0)[br]{\epsfig{figure=tmp/summary-article.ps,width=7.5cm}}}
+\put(0,0){\epsfig{figure=ps/summary,width=7.5cm}}
+\put(445,0){\makebox(0,0)[br]{\epsfig{figure=ps/summary-article,width=7.5cm}}}
}
@end iflatex
@end iftex
@menu
-* Summary Buffer Lines:: You can specify how summary lines should look.
-* To From Newsgroups:: How to not display your own name.
-* Summary Buffer Mode Line:: You can say how the mode line should look.
-* Summary Highlighting:: Making the summary buffer all pretty and nice.
+* Summary Buffer Lines:: You can specify how summary lines should look.
+* To From Newsgroups:: How to not display your own name.
+* Summary Buffer Mode Line:: You can say how the mode line should look.
+* Summary Highlighting:: Making the summary buffer all pretty and nice.
@end menu
@findex mail-extract-address-components
lines as a normal @code{format} string, with some extensions
(@pxref{Formatting Variables}).
-The default string is @samp{%U%R%z%I%(%[%4L: %-20,20n%]%) %s\n}.
+There should always be a colon or a point position marker on the line;
+the cursor always moves to the point position marker or the colon after
+performing an operation. (Of course, Gnus wouldn't be Gnus if it wasn't
+possible to change this. Just write a new function
+@code{gnus-goto-colon} which does whatever you like with the cursor.)
+@xref{Positioning Point}.
-The following format specification characters are understood:
+The default string is @samp{%U%R%z%I%(%[%4L: %-23,23n%]%) %s\n}.
+
+The following format specification characters and extended format
+specification(s) are understood:
@table @samp
@item N
@item L
Number of lines in the article.
@item c
-Number of characters in the article. This specifier is not supported in some
-methods (like nnfolder).
+Number of characters in the article. This specifier is not supported
+in some methods (like nnfolder).
@item I
Indentation based on thread level (@pxref{Customizing Threading}).
+@item B
+A complex trn-style thread tree, showing response-connecting trace
+lines.
@item T
Nothing if the article is a root and lots of spaces if it isn't (it
pushes everything after it off the screen).
@item <
Twenty minus thread level spaces.
@item U
-Unread.
+Unread. @xref{Read Articles}.
@item R
This misleadingly named specifier is the @dfn{secondary mark}. This
mark will say whether the article has been replied to, has been cached,
-or has been saved.
+or has been saved. @xref{Other Marks}.
@item i
Score as a number (@pxref{Scoring}).
The line number.
@item O
Download mark.
+@item &user-date;
+Age sensitive date format. Various date format is defined in
+@code{gnus-user-date-format-alist}.
@item u
User defined specifier. The next character in the format string should
be a letter. Gnus will call the function
into the summary just like information from any other summary specifier.
@end table
+Text between @samp{%(} and @samp{%)} will be highlighted with
+@code{gnus-mouse-face} when the mouse point is placed inside the area.
+There can only be one such area.
+
The @samp{%U} (status), @samp{%R} (replied) and @samp{%z} (zcore) specs
have to be handled with care. For reasons of efficiency, Gnus will
compute what column these characters will end up in, and ``hard-code''
'(To Newsgroups))
(setq nnmail-extra-headers gnus-extra-headers)
(setq gnus-summary-line-format
- "%U%R%z%I%(%[%4L: %-20,20f%]%) %s\n")
+ "%U%R%z%I%(%[%4L: %-23,23f%]%) %s\n")
(setq gnus-ignored-from-addresses
"Your Name Here")
@end lisp
@cindex selecting articles
@menu
-* Choosing Commands:: Commands for choosing articles.
-* Choosing Variables:: Variables that influence these commands.
+* Choosing Commands:: Commands for choosing articles.
+* Choosing Variables:: Variables that influence these commands.
@end menu
@kindex G b (Summary)
@kindex , (Summary)
@findex gnus-summary-best-unread-article
-Go to the article with the highest score
-(@code{gnus-summary-best-unread-article}).
+Go to the unread article with the highest score
+(@code{gnus-summary-best-unread-article}). If given a prefix argument,
+go to the first unread article that has a score over the default score.
@item G l
@itemx l
encoded in the @code{cn-gb-2312} charset. If you have
@lisp
-(setq gnus-summary-show-article-charset-alist
- '((1 . cn-gb-2312)
+(setq gnus-summary-show-article-charset-alist
+ '((1 . cn-gb-2312)
(2 . big5)))
@end lisp
* Summary Mail Commands:: Sending mail.
* Summary Post Commands:: Sending news.
* Summary Message Commands:: Other Message-related commands.
-* Canceling and Superseding:: ``Whoops, I shouldn't have called him that.''
+* Canceling and Superseding::
@end menu
@code{Reply-to}) and @code{Cc} headers in all the process/prefixed
articles. This command uses the process/prefix convention.
-@item S W
-@kindex S W (Summary)
-@findex gnus-summary-wide-reply-with-original
-Mail a very wide reply to the current article and include the original
-message (@code{gnus-summary-wide-reply-with-original}). This command uses
-the process/prefix convention.
-
@item S o m
@itemx C-c C-f
@kindex S o m (Summary)
@kindex S m (Summary)
@findex gnus-summary-mail-other-window
@c @icon{gnus-summary-mail-originate}
-Send a mail to some other person
-(@code{gnus-summary-mail-other-window}).
+Prepare a mail (@code{gnus-summary-mail-other-window}). By default, use
+the posting style of the current group. If given a prefix, disable that.
+If the prefix is 1, prompt for a group name to find the posting style.
+
+@item S i
+@itemx i
+@kindex i (Summary)
+@kindex S i (Summary)
+@findex gnus-summary-news-other-window
+Prepare a news (@code{gnus-summary-news-other-window}). By default,
+post to the current group. If given a prefix, disable that. If the
+prefix is 1, prompt for a group to post to.
+
+This function actually prepares a news even when using mail groups.
+This is useful for "posting" messages to mail groups without actually
+sending them over the network: they're just saved directly to the group
+in question. The corresponding back end must have a request-post method
+for this to work though.
@item S D b
@kindex S D b (Summary)
@end table
-Also @pxref{(message)Header Commands} for more information.
+Also @xref{Header Commands, ,Header Commands, message, The Message
+Manual}, for more information.
@node Summary Post Commands
@kindex S p (Summary)
@findex gnus-summary-post-news
@c @icon{gnus-summary-post-news}
-Post an article to the current group
-(@code{gnus-summary-post-news}).
+Prepare for posting an article (@code{gnus-summary-post-news}). By
+default, post to the current group. If given a prefix, disable that.
+If the prefix is 1, prompt for another group instead.
@item S f
@itemx f
@kindex S o p (Summary)
@findex gnus-summary-post-forward
Forward the current article to a newsgroup
-(@code{gnus-summary-post-forward}).
+(@code{gnus-summary-post-forward}).
If no prefix is given, the message is forwarded according to the value
of (@code{message-forward-as-mime}) and
(@code{message-forward-show-mml}); if the prefix is 1, decode the
(@code{gnus-uu-post-news}). (@pxref{Uuencoding and Posting}).
@end table
-Also @pxref{(message)Header Commands} for more information.
+Also @xref{Header Commands, ,Header Commands, message, The Message
+Manual}, for more information.
@node Summary Message Commands
Just remember, kids: There is no 'c' in 'supersede'.
+@node Delayed Articles
+@section Delayed Articles
+@cindex delayed sending
+@cindex send delayed
+
+Sometimes, you might wish to delay the sending of a message. For
+example, you might wish to arrange for a message to turn up just in time
+to remind your about the birthday of your Significant Other. For this,
+there is the @code{gnus-delay} package. Setup is simple:
+
+@lisp
+(gnus-delay-initialize)
+@end lisp
+
+@findex gnus-delay-article
+Normally, to send a message you use the @kbd{C-c C-c} command from
+Message mode. To delay a message, use @kbd{C-c C-j}
+(@code{gnus-delay-article}) instead. This will ask you for how long the
+message should be delayed. Possible answers are:
+
+@itemize @bullet
+@item
+A time span. Consists of an integer and a letter. For example,
+@code{42d} means to delay for 42 days. Available letters are @code{m}
+(minutes), @code{h} (hours), @code{d} (days), @code{w} (weeks), @code{M}
+(months) and @code{Y} (years).
+
+@item
+A specific date. Looks like @code{YYYYY-MM-DD}. The message will be
+delayed until that day, at a specific time (eight o'clock by default).
+See also @code{gnus-delay-default-hour}.
+
+@item
+A specific time of day. Given in @code{hh:mm} format, 24h, no am/pm
+stuff. The deadline will be at that time today, except if that time has
+already passed, then it's at the given time tomorrow. So if it's ten
+o'clock in the morning and you specify @code{11:15}, then the deadline
+is one hour and fifteen minutes hence. But if you specify @code{9:20},
+that means a time tomorrow.
+@end itemize
+
+The action of the @code{gnus-delay-article} command is influenced by a
+couple of variables:
+
+@table @code
+@item gnus-delay-default-hour
+@vindex gnus-delay-default-hour
+When you specify a specific date, the message will be due on that hour
+on the given date. Possible values are integers 0 through 23.
+
+@item gnus-delay-default-delay
+@vindex gnus-delay-default-delay
+This is a string and gives the default delay. It can be of any of the
+formats described above.
+
+@item gnus-delay-group
+@vindex gnus-delay-group
+Delayed articles will be kept in this group on the drafts server until
+they are due. You probably don't need to change this. The default
+value is @code{"delayed"}.
+
+@item gnus-delay-header
+@vindex gnus-delay-header
+The deadline for each article will be stored in a header. This variable
+is a string and gives the header name. You probably don't need to
+change this. The default value is @code{"X-Gnus-Delayed"}.
+@end table
+
+The way delaying works is like this: when you use the
+@code{gnus-delay-article} command, you give a certain delay. Gnus
+calculates the deadline of the message and stores it in the
+@code{X-Gnus-Delayed} header and puts the message in the
+@code{nndraft:delayed} group.
+
+And whenever you get new news, Gnus looks through the group for articles
+which are due and sends them. It uses the @code{gnus-delay-send-queue}
+function for this. By default, this function is added to the hook
+@code{gnus-get-new-news-hook}. But of course, you can change this.
+Maybe you want to use the demon to send drafts? Just tell the demon to
+execute the @code{gnus-delay-send-queue} function.
+
+@table @code
+@item gnus-delay-initialize
+@findex gnus-delay-initialize
+By default, this function installs the @kbd{C-c C-j} key binding in
+Message mode and @code{gnus-delay-send-queue} in
+@code{gnus-get-new-news-hook}. But it accepts two optional arguments,
+@code{no-keymap} and @code{no-check}. If @code{no-keymap} is non-nil,
+the @kbd{C-c C-j} binding is not intalled. If @code{no-check} is
+non-nil, @code{gnus-get-new-news-hook} is not changed.
+
+For example, @code{(gnus-delay-initialize nil t)} means to change the
+keymap but not to change @code{gnus-get-new-news-hook}. Presumably, you
+want to use the demon for sending due delayed articles. Just don't
+forget to set that up :-)
+@end table
+
@node Marking Articles
@section Marking Articles
In addition, you also have marks that do not affect readedness.
@menu
-* Unread Articles:: Marks for unread articles.
-* Read Articles:: Marks for read articles.
-* Other Marks:: Marks that do not affect readedness.
+* Unread Articles:: Marks for unread articles.
+* Read Articles:: Marks for read articles.
+* Other Marks:: Marks that do not affect readedness.
@end menu
@ifinfo
@item M
@vindex gnus-duplicate-mark
Article marked as read by duplicate suppression
-(@code{gnus-duplicated-mark}). @xref{Duplicate Suppression}.
+(@code{gnus-duplicate-mark}). @xref{Duplicate Suppression}.
@end table
(@code{gnus-replied-mark}).
@vindex gnus-forwarded-mark
-All articles that you have forwarded will be marked with an @samp{O} in
+All articles that you have forwarded will be marked with an @samp{F} in
the second column (@code{gnus-forwarded-mark}).
+@vindex gnus-recent-mark
+Articles that are ``recently'' arrived in the group will be marked
+with an @samp{N} in the second column (@code{gnus-recent-mark}). Most
+back end doesn't support the mark, in which case it's not shown.
+
@item
@vindex gnus-cached-mark
Articles stored in the article cache will be marked with an @samp{*} in
(@code{gnus-saved-mark}).
@item
+@vindex gnus-recent-mark
+Articles that according to the back end haven't been seen by the user
+before are marked with a @samp{N} in the second column
+(@code{gnus-recent-mark}). Note that not all back ends support this
+mark, in which case it simply never appear.
+
+@item
+@vindex gnus-unseen-mark
+Articles that haven't been seen by the user before are marked with a
+@samp{.} in the second column (@code{gnus-unseen-mark}).
+
+@item
@vindex gnus-not-empty-thread-mark
@vindex gnus-empty-thread-mark
If the @samp{%e} spec is used, the presence of threads or not will be
@item M H
@kindex M H (Summary)
@findex gnus-summary-catchup-to-here
-Catchup the current group to point
+Catchup the current group to point (before the point)
(@code{gnus-summary-catchup-to-here}).
+@item M h
+@kindex M h (Summary)
+@findex gnus-summary-catchup-from-here
+Catchup the current group from point (after the point)
+(@code{gnus-summary-catchup-from-here}).
+
@item C-w
@kindex C-w (Summary)
@findex gnus-summary-mark-region-as-read
@kindex / / (Summary)
@findex gnus-summary-limit-to-subject
Limit the summary buffer to articles that match some subject
-(@code{gnus-summary-limit-to-subject}).
+(@code{gnus-summary-limit-to-subject}). If given a prefix, exclude
+matching articles.
@item / a
@kindex / a (Summary)
@findex gnus-summary-limit-to-author
Limit the summary buffer to articles that match some author
-(@code{gnus-summary-limit-to-author}).
+(@code{gnus-summary-limit-to-author}). If given a prefix, exclude
+matching articles.
@item / x
@kindex / x (Summary)
@findex gnus-summary-limit-to-extra
Limit the summary buffer to articles that match one of the ``extra''
headers (@pxref{To From Newsgroups})
-(@code{gnus-summary-limit-to-extra}).
+(@code{gnus-summary-limit-to-extra}). If given a prefix, exclude
+matching articles.
@item / u
@itemx x
Limit the summary buffer to articles that have a score at or above some
score (@code{gnus-summary-limit-to-score}).
+@item / p
+@kindex / p (Summary)
+@findex gnus-summary-limit-to-display-parameter
+Limit the summary buffer to articles that satisfy the @code{display}
+group parameter predicate
+(@code{gnus-summary-limit-to-display-parameter}). See @pxref{Group
+Parameters} for more on this predicate.
+
@item / E
@itemx M S
@kindex M S (Summary)
(@code{gnus-summary-limit-mark-excluded-as-read}). If given a prefix,
also mark excluded ticked and dormant articles as read.
+@item / N
+@kindex / N (Summary)
+@findex gnus-summary-insert-new-articles
+Insert all new articles in the summary buffer. It scans for new emails
+if @var{back-end}@code{-get-new-mail} is non-@code{nil}.
+
+@item / o
+@kindex / o (Summary)
+@findex gnus-summary-insert-old-articles
+Insert all old articles in the summary buffer. If given a numbered
+prefix, fetch this number of articles.
+
@end table
@menu
-* Customizing Threading:: Variables you can change to affect the threading.
-* Thread Commands:: Thread based commands in the summary buffer.
+* Customizing Threading:: Variables you can change to affect the threading.
+* Thread Commands:: Thread based commands in the summary buffer.
@end menu
@cindex customizing threading
@menu
-* Loose Threads:: How Gnus gathers loose threads into bigger threads.
-* Filling In Threads:: Making the threads displayed look fuller.
-* More Threading:: Even more variables for fiddling with threads.
-* Low-Level Threading:: You thought it was over... but you were wrong!
+* Loose Threads:: How Gnus gathers loose threads into bigger threads.
+* Filling In Threads:: Making the threads displayed look fuller.
+* More Threading:: Even more variables for fiddling with threads.
+* Low-Level Threading:: You thought it was over... but you were wrong!
@end menu
@iftex
@iflatex
\gnusfigure{The Summary Buffer}{390}{
-\put(0,0){\epsfig{figure=tmp/summary-adopt.ps,width=7.5cm}}
-\put(445,0){\makebox(0,0)[br]{\epsfig{figure=tmp/summary-empty.ps,width=7.5cm}}}
-\put(0,400){\makebox(0,0)[tl]{\epsfig{figure=tmp/summary-none.ps,width=7.5cm}}}
-\put(445,400){\makebox(0,0)[tr]{\epsfig{figure=tmp/summary-dummy.ps,width=7.5cm}}}
+\put(0,0){\epsfig{figure=ps/summary-adopt,width=7.5cm}}
+\put(445,0){\makebox(0,0)[br]{\epsfig{figure=ps/summary-empty,width=7.5cm}}}
+\put(0,400){\makebox(0,0)[tl]{\epsfig{figure=ps/summary-none,width=7.5cm}}}
+\put(445,400){\makebox(0,0)[tr]{\epsfig{figure=ps/summary-dummy,width=7.5cm}}}
}
@end iflatex
@end iftex
connect as many loose threads as possible, you should set this variable
to @code{some} or a number. If you set it to a number, no more than
that number of extra old headers will be fetched. In either case,
-fetching old headers only works if the backend you are using carries
+fetching old headers only works if the back end you are using carries
overview files---this would normally be @code{nntp}, @code{nnspool} and
@code{nnml}. Also remember that if the root of the thread has been
expired by the server, there's not much Gnus can do about that.
@item gnus-read-all-available-headers
@vindex gnus-read-all-available-headers
This is a rather obscure variable that few will find useful. It's
-intended for those non-news newsgroups where the backend has to fetch
+intended for those non-news newsgroups where the back end has to fetch
quite a lot to present the summary buffer, and where it's impossible to
go back to parents of articles. This is mostly the case in the
web-based groups, like the @code{nnultimate} groups.
@table @kbd
@item T k
-@itemx M-C-k
+@itemx C-M-k
@kindex T k (Summary)
-@kindex M-C-k (Summary)
+@kindex C-M-k (Summary)
@findex gnus-summary-kill-thread
Mark all articles in the current (sub-)thread as read
(@code{gnus-summary-kill-thread}). If the prefix argument is positive,
articles instead.
@item T l
-@itemx M-C-l
+@itemx C-M-l
@kindex T l (Summary)
-@kindex M-C-l (Summary)
+@kindex C-M-l (Summary)
@findex gnus-summary-lower-thread
Lower the score of the current (sub-)thread
(@code{gnus-summary-lower-thread}).
@item T n
@kindex T n (Summary)
-@itemx M-C-n
-@kindex M-C-n (Summary)
+@itemx C-M-n
+@kindex C-M-n (Summary)
@itemx M-down
@kindex M-down (Summary)
@findex gnus-summary-next-thread
@item T p
@kindex T p (Summary)
-@itemx M-C-p
-@kindex M-C-p (Summary)
+@itemx C-M-p
+@kindex C-M-p (Summary)
@itemx M-up
@kindex M-up (Summary)
@findex gnus-summary-prev-thread
@vindex gnus-use-article-prefetch
You can control how many articles are to be pre-fetched by setting
@code{gnus-use-article-prefetch}. This is 30 by default, which means
-that when you read an article in the group, the backend will pre-fetch
-the next 30 articles. If this variable is @code{t}, the backend will
+that when you read an article in the group, the back end will pre-fetch
+the next 30 articles. If this variable is @code{t}, the back end will
pre-fetch all the articles it can without bound. If it is
@code{nil}, no pre-fetching will be done.
(@code{gnus-summary-save-article-vm}).
@item O p
+@itemx |
@kindex O p (Summary)
+@kindex | (Summary)
@findex gnus-summary-pipe-output
Save the current article in a pipe. Uhm, like, what I mean is---Pipe
the current article to a process (@code{gnus-summary-pipe-output}).
+
+@item O P
+@kindex O P (Summary)
+@findex gnus-summary-muttprint
+@vindex gnus-summary-muttprint-program
+Save the current article into muttprint. That is, print it using the
+external program Muttprint (see
+@uref{http://muttprint.sourceforge.net/}). The program name and
+options to use is controlled by the variable
+@code{gnus-summary-muttprint-program}. (@code{gnus-summary-muttprint}).
+
@end table
@vindex gnus-prompt-before-saving
the @code{gnus-file-save-name} variable to get a file name to save the
article in. The default is @code{gnus-numeric-save-name}.
+@item gnus-summary-write-to-file
+@findex gnus-summary-write-to-file
+Write the article straight to an ordinary file. The file is
+overwritten if it exists. Uses the function in the
+@code{gnus-file-save-name} variable to get a file name to save the
+article in. The default is @code{gnus-numeric-save-name}.
+
@item gnus-summary-save-body-in-file
@findex gnus-summary-save-body-in-file
Append the article body to an ordinary file. Uses the function in the
@lisp
(setq gnus-use-long-file-name '(not-save)) ; to get a hierarchy
-(setq gnus-default-article-saver 'gnus-summary-save-in-file) ; no encoding
+(setq gnus-default-article-saver
+ 'gnus-summary-save-in-file) ; no encoding
@end lisp
Then just save with @kbd{o}. You'd then read this hierarchy with
encoded in some way or other. Gnus can decode them for you.
@menu
-* Uuencoded Articles:: Uudecode articles.
-* Shell Archives:: Unshar articles.
-* PostScript Files:: Split PostScript.
-* Other Files:: Plain save and binhex.
-* Decoding Variables:: Variables for a happy decoding.
-* Viewing Files:: You want to look at the result of the decoding?
+* Uuencoded Articles:: Uudecode articles.
+* Shell Archives:: Unshar articles.
+* PostScript Files:: Split PostScript.
+* Other Files:: Plain save and binhex.
+* Decoding Variables:: Variables for a happy decoding.
+* Viewing Files:: You want to look at the result of the decoding?
@end menu
@cindex series
Adjective, not verb.
@menu
-* Rule Variables:: Variables that say how a file is to be viewed.
-* Other Decode Variables:: Other decode variables.
-* Uuencoding and Posting:: Variables for customizing uuencoding.
+* Rule Variables:: Variables that say how a file is to be viewed.
+* Other Decode Variables:: Other decode variables.
+* Uuencoding and Posting:: Variables for customizing uuencoding.
@end menu
* Article Washing:: Lots of way-neat functions to make life better.
* Article Buttons:: Click on URLs, Message-IDs, addresses and the like.
* Article Date:: Grumble, UT!
+* Article Display:: Display various stuff---X-Face, Picons, Smileys
* Article Signature:: What is a signature?
* Article Miscellania:: Various other stuff.
@end menu
@item W Q
@kindex W Q (Summary)
-@findex gnus-article-fill-long-lines
+@findex gnus-article-fill-long-lines
Fill long lines (@code{gnus-article-fill-long-lines}).
@item W C
readable to me. Note that the this is usually done automatically by
Gnus if the message in question has a @code{Content-Transfer-Encoding}
header that says that this encoding has been done.
+If a prefix is given, a charset will be asked for.
@item W 6
@kindex W 6 (Summary)
automatically by Gnus if the message in question has a
@code{Content-Transfer-Encoding} header that says that this encoding has
been done.
+If a prefix is given, a charset will be asked for.
@item W Z
@kindex W Z (Summary)
@item W h
@kindex W h (Summary)
@findex gnus-article-wash-html
-Treat HTML (@code{gnus-article-wash-html}).
+Treat HTML (@code{gnus-article-wash-html}).
Note that the this is usually done automatically by Gnus if the message
in question has a @code{Content-Type} header that says that this type
has been done.
-
-@item W f
-@kindex W f (Summary)
-@cindex x-face
-@findex gnus-article-display-x-face
-@findex gnus-article-x-face-command
-@vindex gnus-article-x-face-command
-@vindex gnus-article-x-face-too-ugly
-@iftex
-@iflatex
-\include{xface}
-@end iflatex
-@end iftex
-@c @anchor{X-Face}
-Look for and display any X-Face headers
-(@code{gnus-article-display-x-face}). The command executed by this
-function is given by the @code{gnus-article-x-face-command} variable.
-If this variable is a string, this string will be executed in a
-sub-shell. If it is a function, this function will be called with the
-face as the argument. If the @code{gnus-article-x-face-too-ugly} (which
-is a regexp) matches the @code{From} header, the face will not be shown.
-The default action under Emacs is to fork off the @code{display}
-program@footnote{@code{display} is from the ImageMagick package. For the
-@code{uncompface} and @code{icontopbm} programs look for a package
-like `compface' or `faces-xface' on a GNU/Linux system.}
-to view the face. Under XEmacs or Emacs 21+ with suitable image
-support, the default action is to display the face before the
-@code{From} header. (It's nicer if XEmacs has been compiled with X-Face
-support---that will make display somewhat faster. If there's no native
-X-Face support, Gnus will try to convert the @code{X-Face} header using
-external programs from the @code{pbmplus} package and
-friends.@footnote{On a GNU/Linux system look for packages with names
-like @code{netpbm} or @code{libgr-progs}.}) If you
-want to have this function in the display hook, it should probably come
-last.
+If a prefix is given, a charset will be asked for.
@item W b
@kindex W b (Summary)
Add clickable buttons to the article headers
(@code{gnus-article-add-buttons-to-head}).
+@item W p
+@kindex W p (Summary)
+@findex gnus-article-verify-x-pgp-sig
+Verify a signed control message (@code{gnus-article-verify-x-pgp-sig}).
+Control messages such as @code{newgroup} and @code{checkgroups} are
+usually signed by the hierarchy maintainer. You need to add the PGP
+public key of the maintainer to your keyring to verify the
+message.@footnote{PGP keys for many hierarchies are available at
+@uref{ftp://ftp.isc.org/pub/pgpcontrol/README.html}}
+
+@item W s
+@kindex W s (Summary)
+@findex gnus-summary-force-verify-and-decrypt
+Verify a signed (PGP, PGP/MIME or S/MIME) message
+(@code{gnus-summary-force-verify-and-decrypt}).
+
+@item W u
+@kindex W u (Summary)
+@findex gnus-article-treat-unfold-headers
+Unfold folded header lines (@code{gnus-article-treat-unfold-headers}).
+
+@item W n
+@kindex W n (Summary)
+@findex gnus-article-treat-fold-newsgroups
+Fold the @code{Newsgroups} and @code{Followup-To} headers
+(@code{gnus-article-treat-fold-newsgroups}).
+
@item W W H
@kindex W W H (Summary)
@findex gnus-article-strip-headers-from-body
(@code{gnus-article-date-lapsed}). It looks something like:
@example
-X-Sent: 9 years, 6 weeks, 4 days, 9 hours, 3 minutes, 28 seconds ago
+X-Sent: 6 weeks, 4 days, 1 hour, 3 minutes, 8 seconds ago
@end example
The value of @code{gnus-article-date-lapsed-new-header} determines
preferred format automatically.
+@node Article Display
+@subsection Article Display
+@cindex picons
+@cindex x-face
+@cindex smileys
+
+These commands add various frivolous display gimmics to the article
+buffer in Emacs versions that support them.
+
+@code{X-Face} headers are small black-and-white images supplied by the
+message headers (@pxref{X-Face}).
+
+Picons, on the other hand, reside on your own system, and Gnus will
+try to match the headers to what you have (@pxref{Picons}).
+
+Smileys are those little @samp{:-)} symbols that people like to litter
+their messages with (@pxref{Smileys}).
+
+All these functions are toggles--if the elements already exist,
+they'll be removed.
+
+@table @kbd
+@item W D x
+@kindex W D x (Summary)
+@findex gnus-article-display-x-face
+Display an @code{X-Face} in the @code{From} header.
+(@code{gnus-article-display-x-face}).
+
+@item W D s
+@kindex W D s (Summary)
+@findex gnus-article-toggle-smiley
+Toggle whether to display smileys
+(@code{gnus-article-toggle-smiley}).
+
+@item W D f
+@kindex W D f (Summary)
+@findex gnus-treat-from-picon
+Piconify the @code{From} header (@code{gnus-treat-from-picon}).
+
+@item W D m
+@kindex W D m (Summary)
+@findex gnus-treat-mail-picon
+Piconify all mail headers (i. e., @code{Cc}, @code{To})
+(@code{gnus-treat-mail-picon}).
+
+@item W D n
+@kindex W D n (Summary)
+@findex gnus-treat-newsgroups-picon
+Piconify all news headers (i. e., @code{Newsgroups} and
+@code{Followup-To}) (@code{gnus-treat-from-picon}).
+
+@end table
+
+
+
@node Article Signature
@subsection Article Signature
@cindex signatures
@kindex A t (Summary)
@findex gnus-article-babel
Translate the article from one language to another
-(@code{gnus-article-babel}).
+(@code{gnus-article-babel}).
@end table
@vindex gnus-unbuttonized-mime-types
This is a list of regexps. @sc{mime} types that match a regexp from
this list won't have @sc{mime} buttons inserted unless they aren't
-displayed. The default value is @code{(".*/.*")}.
+displayed or this variable is overriden by
+@code{gnus-buttonized-mime-types}. The default value is
+@code{(".*/.*")}.
+
+@item gnus-buttonized-mime-types
+@vindex gnus-buttonized-mime-types
+This is a list of regexps. @sc{mime} types that match a regexp from
+this list will have @sc{mime} buttons inserted unless they aren't
+displayed. This variable overrides
+@code{gnus-unbuttonized-mime-types}. The default value is @code{nil}.
+
+To see e.g. security buttons but no other buttons, you could set this
+variable to @code{("multipart/signed")} and leave
+@code{gnus-unbuttonized-mime-types} to the default value.
@item gnus-article-mime-part-function
@vindex gnus-article-mime-part-function
@item gnus-mime-multipart-functions
Alist of @sc{mime} multipart types and functions to handle them.
+@vindex mm-file-name-rewrite-functions
+@item mm-file-name-rewrite-functions
+List of functions used for rewriting file names of @sc{mime} parts.
+Each function takes a file name as input and returns a file name.
+
+Ready-made functions include@*
+@code{mm-file-name-delete-whitespace},
+@code{mm-file-name-trim-whitespace},
+@code{mm-file-name-collapse-whitespace}, and
+@code{mm-file-name-replace-whitespace}. The later uses the value of
+the variable @code{mm-file-name-replace-whitespace} to replace each
+whitespace character in a file name with that string; default value
+is @code{"_"} (a single underscore).
+@findex mm-file-name-delete-whitespace
+@findex mm-file-name-trim-whitespace
+@findex mm-file-name-collapse-whitespace
+@findex mm-file-name-replace-whitespace
+@vindex mm-file-name-replace-whitespace
+
+The standard functions @code{capitalize}, @code{downcase},
+@code{upcase}, and @code{upcase-initials} may be useful, too.
+
+Everybody knows that whitespace characters in file names are evil,
+except those who don't know. If you receive lots of attachments from
+such unenlightened users, you can make live easier by adding
+
+@lisp
+(setq mm-file-name-rewrite-functions
+ '(mm-file-name-trim-whitespace
+ mm-file-name-collapse-whitespace
+ mm-file-name-replace-whitespace))
+@end lisp
+
+@noindent
+to your @file{.gnus} file.
+
@end table
@vindex gnus-group-charset-alist
This knowledge is encoded in the @code{gnus-group-charset-alist}
-variable, which is an alist of regexps (to match full group names) and
-default charsets to be used when reading these groups.
+variable, which is an alist of regexps (use the first item to match full
+group names) and default charsets to be used when reading these groups.
In addition, some people do use soi-disant @sc{mime}-aware agents that
-aren't. These blithely mark messages as being in @code{iso-8859-1} even
-if they really are in @code{koi-8}. To help here, the
+aren't. These blithely mark messages as being in @code{iso-8859-1}
+even if they really are in @code{koi-8}. To help here, the
@code{gnus-newsgroup-ignored-charsets} variable can be used. The
-charsets that are listed here will be ignored. The variable can be set
-on a group-by-group basis using the group parameters (@pxref{Group
-Parameters}). The default value is @code{(unknown-8bit)}, which is
-something some agents insist on having in there.
+charsets that are listed here will be ignored. The variable can be
+set on a group-by-group basis using the group parameters (@pxref{Group
+Parameters}). The default value is @code{(unknown-8bit x-unknown)},
+which includes values some agents insist on having in there.
@vindex gnus-group-posting-charset-alist
When posting, @code{gnus-group-posting-charset-alist} is used to
@vindex gnus-ps-print-hook
@findex gnus-summary-print-article
Generate and print a PostScript image of the article buffer
-(@code{gnus-summary-print-article}). @code{gnus-ps-print-hook} will be
-run just before printing the buffer.
+(@code{gnus-summary-print-article}). @code{gnus-ps-print-hook} will
+be run just before printing the buffer. An alternative way to print
+article is to use Muttprint (@pxref{Saving Articles}).
@end table
by giving this command a prefix.
@vindex gnus-refer-article-method
-If the group you are reading is located on a backend that does not
+If the group you are reading is located on a back end that does not
support fetching by @code{Message-ID} very well (like @code{nnspool}),
you can set @code{gnus-refer-article-method} to an @sc{nntp} method. It
would, perhaps, be best if the @sc{nntp} server you consult is the one
(nnweb "refer" (nnweb-type dejanews))))
@end lisp
-Most of the mail backends support fetching by @code{Message-ID}, but do
-not do a particularly excellent job at it. That is, @code{nnmbox} and
-@code{nnbabyl} are able to locate articles from any groups, while
-@code{nnml} and @code{nnfolder} are only able to locate articles that
-have been posted to the current group. (Anything else would be too time
-consuming.) @code{nnmh} does not support this at all.
+Most of the mail back ends support fetching by @code{Message-ID}, but
+do not do a particularly excellent job at it. That is, @code{nnmbox}
+and @code{nnbabyl} are able to locate articles from any groups, while
+@code{nnml}, @code{nnfolder} and @code{nnimap}1 are only able to locate
+articles that have been posted to the current group. (Anything else
+would be too time consuming.) @code{nnmh} does not support this at
+all.
@node Alternative Approaches
buffer is one of these, minimizing the tree window will also resize all
other windows displayed next to it.
+You may also wish to add the following hook to keep the window minimized
+at all times:
+
+@lisp
+(add-hook 'gnus-configure-windows-hook
+ 'gnus-tree-perhaps-minimize)
+@end lisp
+
@item gnus-generate-tree-function
@vindex gnus-generate-tree-function
@findex gnus-generate-horizontal-tree
(article 1.0))))
@end lisp
-@xref{Windows Configuration}.
+@xref{Window Layout}.
@node Mail Group Commands
@item B e
@kindex B e (Summary)
@findex gnus-summary-expire-articles
-Expire all expirable articles in the group
-(@code{gnus-summary-expire-articles}).
+Run all expirable articles in the current group through the expiry
+process (@code{gnus-summary-expire-articles}). That is, delete all
+expirable articles in the group that have been around for a while.
+(@pxref{Expiring Mail}).
-@item B M-C-e
-@kindex B M-C-e (Summary)
+@item B C-M-e
+@kindex B C-M-e (Summary)
@findex gnus-summary-expire-articles-now
Delete all the expirable articles in the group
(@code{gnus-summary-expire-articles-now}). This means that @strong{all}
@vindex gnus-preserve-marks
Move the article from one mail group to another
(@code{gnus-summary-move-article}). Marks will be preserved if
-@var{gnus-preserve-marks} is non-@code{nil} (which is the default).
+@var{gnus-preserve-marks} is non-@code{nil} (which is the default).
@item B c
@kindex B c (Summary)
@section Various Summary Stuff
@menu
-* Summary Group Information:: Information oriented commands.
-* Searching for Articles:: Multiple article commands.
-* Summary Generation Commands:: (Re)generating the summary buffer.
-* Really Various Summary Commands:: Those pesky non-conformant commands.
+* Summary Group Information:: Information oriented commands.
+* Searching for Articles:: Multiple article commands.
+* Summary Generation Commands::
+* Really Various Summary Commands:: Those pesky non-conformant commands.
@end menu
@table @code
articles))
@end lisp
+@vindex gnus-newsgroup-variables
+@item gnus-newsgroup-variables
+A list of newsgroup (summary buffer) local variables, or cons of
+variables and their default values (when the default values are not
+nil), that should be made global while the summary buffer is active.
+These variables can be used to set variables in the group parameters
+while still allowing them to affect operations done in other
+buffers. For example:
+
+@lisp
+(setq gnus-newsgroup-variables
+ '(message-use-followup-to
+ (gnus-visible-headers .
+ "^From:\\|^Newsgroups:\\|^Subject:\\|^Date:\\|^To:")))
+@end lisp
+
@end table
@item M-s
@kindex M-s (Summary)
@findex gnus-summary-search-article-forward
-Search through all subsequent articles for a regexp
+Search through all subsequent (raw) articles for a regexp
(@code{gnus-summary-search-article-forward}).
@item M-r
@kindex M-r (Summary)
@findex gnus-summary-search-article-backward
-Search through all previous articles for a regexp
+Search through all previous (raw) articles for a regexp
(@code{gnus-summary-search-article-backward}).
@item &
some format, you @kbd{C-d} and read these messages in a more convenient
fashion.
-@item M-C-d
-@kindex M-C-d (Summary)
+@item C-M-d
+@kindex C-M-d (Summary)
@findex gnus-summary-read-document
This command is very similar to the one above, but lets you gather
several documents into one biiig group
Expand the summary buffer window (@code{gnus-summary-expand-window}).
If given a prefix, force an @code{article} window configuration.
-@item M-C-e
-@kindex M-C-e (Summary)
+@item C-M-e
+@kindex C-M-e (Summary)
@findex gnus-summary-edit-parameters
Edit the group parameters (@pxref{Group Parameters}) of the current
group (@code{gnus-summary-edit-parameters}).
-@item M-C-a
-@kindex M-C-a (Summary)
+@item C-M-a
+@kindex C-M-a (Summary)
@findex gnus-summary-customize-parameters
Customize the group parameters (@pxref{Group Parameters}) of the current
group (@code{gnus-summary-customize-parameters}).
@node Security
@section Security
-Gnus is able to verify PGP or S/MIME signed messages or decrypt PGP
-encrypted messages.
+Gnus is able to verify signed messages or decrypt encrypted messages.
+The formats that are supported are PGP (plain text, RFC 1991 format),
+PGP/MIME (RFC 2015/3156) and S/MIME, however you need some external
+programs to get things to work:
@enumerate
-@item
+@item
To verify or decrypt PGP messages, you have to install mailcrypt or
-gpg.el.
+gpg.el as well as a OpenPGP implementation (such as GnuPG). @xref{Using GPG}.
+
+@item
+To verify or decrypt S/MIME message, you need to install OpenSSL.
+OpenSSL 0.9.6 or newer is recommended.
@end enumerate
+More information on how to set things up can be found in the message
+manual. @xref{Security, ,Security, message, The Message Manual}.
+
@table @code
@item mm-verify-option
@vindex mm-verify-option
@end table
+@node Mailing List
+@section Mailing List
+
+Gnus understands some mailing list fields of RFC 2369. To enable it,
+either add a `to-list' group parameter (@pxref{Group Parameters}),
+possibly using @kbd{A M} in the summary buffer, or say:
+
+@lisp
+(add-hook 'gnus-summary-mode-hook 'turn-on-gnus-mailing-list-mode)
+@end lisp
+
+That enables the following commands to the summary buffer:
+
+@table @kbd
+
+@item C-c C-n h
+@kindex C-c C-n h (Summary)
+@findex gnus-mailing-list-help
+Send a message to fetch mailing list help, if List-Help field exists.
+
+@item C-c C-n s
+@kindex C-c C-n s (Summary)
+@findex gnus-mailing-list-subscribe
+Send a message to subscribe the mailing list, if List-Subscribe field exists.
+
+@item C-c C-n u
+@kindex C-c C-n u (Summary)
+@findex gnus-mailing-list-unsubscribe
+Send a message to unsubscribe the mailing list, if List-Unsubscribe
+field exists.
+
+@item C-c C-n p
+@kindex C-c C-n p (Summary)
+@findex gnus-mailing-list-post
+Post to the mailing list, if List-Post field exists.
+
+@item C-c C-n o
+@kindex C-c C-n o (Summary)
+@findex gnus-mailing-list-owner
+Send a message to the mailing list owner, if List-Owner field exists.
+
+@item C-c C-n a
+@kindex C-c C-n a (Summary)
+@findex gnus-mailing-list-owner
+Browse the mailing list archive, if List-Archive field exists.
+
+@end table
+
@node Article Buffer
@chapter Article Buffer
@cindex article buffer
tell Gnus otherwise.
@menu
-* Hiding Headers:: Deciding what headers should be displayed.
-* Using MIME:: Pushing articles through @sc{mime} before reading them.
-* Customizing Articles:: Tailoring the look of the articles.
-* Article Keymap:: Keystrokes available in the article buffer.
-* Misc Article:: Other stuff.
+* Hiding Headers:: Deciding what headers should be displayed.
+* Using MIME:: Pushing articles through @sc{mime} before reading them.
+* Customizing Articles:: Tailoring the look of the articles.
+* Article Keymap:: Keystrokes available in the article buffer.
+* Misc Article:: Other stuff.
@end menu
@node Using MIME
-@section Using @sc{mime}
+@section Using MIME
@cindex @sc{mime}
Mime is a standard for waving your hands through the air, aimlessly,
@table @kbd
@findex gnus-article-press-button
@item RET (Article)
+@kindex RET (Article)
@itemx BUTTON-2 (Article)
Toggle displaying of the @sc{mime} object
(@code{gnus-article-press-button}).
@findex gnus-mime-view-part
@item M-RET (Article)
+@kindex M-RET (Article)
@itemx v (Article)
Prompt for a method, and then view the @sc{mime} object using this
method (@code{gnus-mime-view-part}).
+@findex gnus-mime-view-part-as-type
+@item t (Article)
+@kindex t (Article)
+View the @sc{mime} object as if it were a different @sc{mime} media type
+(@code{gnus-mime-view-part-as-type}).
+
+@findex gnus-mime-view-part-as-charset
+@item C (Article)
+@kindex C (Article)
+Prompt for a charset, and then view the @sc{mime} object using this
+charset (@code{gnus-mime-view-part-as-charset}).
+
@findex gnus-mime-save-part
@item o (Article)
+@kindex o (Article)
Prompt for a file name, and then save the @sc{mime} object
(@code{gnus-mime-save-part}).
+@findex gnus-mime-save-part-and-strip
+@item C-o (Article)
+@kindex C-o (Article)
+Prompt for a file name, then save the @sc{mime} object and strip it from
+the article. Then proceed to article editing, where a reasonable
+suggestion is being made on how the altered article should look
+like. The stripped @sc{mime} object will be referred via the
+message/external-body @sc{mime} type.
+(@code{gnus-mime-save-part-and-strip}).
+
@findex gnus-mime-copy-part
@item c (Article)
+@kindex c (Article)
Copy the @sc{mime} object to a fresh buffer and display this buffer
(@code{gnus-mime-copy-part}).
-@findex gnus-mime-view-part-as-type
-@item t (Article)
-View the @sc{mime} object as if it were a different @sc{mime} media type
-(@code{gnus-mime-view-part-as-type}).
-
-@findex gnus-mime-pipe-part
-@item | (Article)
-Output the @sc{mime} object to a process (@code{gnus-mime-pipe-part}).
+@findex gnus-mime-print-part
+@item p (Article)
+@kindex p (Article)
+Print the @sc{mime} object (@code{gnus-mime-print-part}). This
+command respects the @samp{print=} specifications in the
+@file{.mailcap} file.
@findex gnus-mime-inline-part
@item i (Article)
+@kindex i (Article)
Insert the contents of the @sc{mime} object into the buffer
(@code{gnus-mime-inline-part}) as text/plain. If given a prefix, insert
the raw contents without decoding. If given a numerical prefix, you can
@code{gnus-summary-show-article-charset-alist} in @pxref{Paging the
Article}).
+@findex gnus-mime-internalize-part
+@item E (Article)
+@kindex E (Article)
+View the @sc{mime} object with an internal viewer. If no internal
+viewer is available, use an external viewer
+(@code{gnus-mime-internalize-part}).
+
+@findex gnus-mime-externalize-part
+@item e (Article)
+@kindex e (Article)
+View the @sc{mime} object with an external viewer.
+(@code{gnus-mime-externalize-part}).
+
+@findex gnus-mime-pipe-part
+@item | (Article)
+@kindex | (Article)
+Output the @sc{mime} object to a process (@code{gnus-mime-pipe-part}).
+
@findex gnus-mime-action-on-part
@item . (Article)
+@kindex . (Article)
Interactively run an action on the @sc{mime} object
(@code{gnus-mime-action-on-part}).
possible but those listed are probably sufficient for most people.
@table @code
-@item gnus-treat-highlight-signature (t, last)
@item gnus-treat-buttonize (t, integer)
@item gnus-treat-buttonize-head (head)
+@item gnus-treat-capitalize-sentences (t, integer)
+@item gnus-treat-date-english (head)
+@item gnus-treat-date-iso8601 (head)
+@item gnus-treat-date-lapsed (head)
+@item gnus-treat-date-local (head)
+@item gnus-treat-date-original (head)
+@item gnus-treat-date-user-defined (head)
+@item gnus-treat-date-ut (head)
+@item gnus-treat-display-picons (head)
+@item gnus-treat-display-smileys (t, integer)
+@item gnus-treat-display-xface (head)
@item gnus-treat-emphasize (t, head, integer)
@item gnus-treat-fill-article (t, integer)
-@item gnus-treat-strip-cr (t, integer)
-@item gnus-treat-hide-headers (head)
+@item gnus-treat-fill-long-lines (t, integer)
@item gnus-treat-hide-boring-headers (head)
-@item gnus-treat-hide-signature (t, last)
@item gnus-treat-hide-citation (t, integer)
@item gnus-treat-hide-citation-maybe (t, integer)
-@item gnus-treat-strip-pgp (t, last, integer)
-@item gnus-treat-strip-pem (t, last, integer)
-@item gnus-treat-highlight-headers (head)
+@item gnus-treat-hide-headers (head)
+@item gnus-treat-hide-signature (t, last)
@item gnus-treat-highlight-citation (t, integer)
+@item gnus-treat-highlight-headers (head)
@item gnus-treat-highlight-signature (t, last, integer)
-@item gnus-treat-date-ut (head)
-@item gnus-treat-date-local (head)
-@item gnus-treat-date-english (head)
-@item gnus-treat-date-lapsed (head)
-@item gnus-treat-date-original (head)
-@item gnus-treat-date-iso8601 (head)
-@item gnus-treat-date-user-defined (head)
+@item gnus-treat-overstrike (t, integer)
+@item gnus-treat-play-sounds
+@item gnus-treat-strip-cr (t, integer)
@item gnus-treat-strip-headers-in-body (t, integer)
-@item gnus-treat-strip-trailing-blank-lines (t, last, integer)
@item gnus-treat-strip-leading-blank-lines (t, integer)
@item gnus-treat-strip-multiple-blank-lines (t, integer)
-@item gnus-treat-overstrike (t, integer)
-@item gnus-treat-display-xface (head)
-@item gnus-treat-display-smileys (t, integer)
-@item gnus-treat-display-picons (head)
-@item gnus-treat-capitalize-sentences (t, integer)
-@item gnus-treat-fill-long-lines (t, integer)
-@item gnus-treat-play-sounds
+@item gnus-treat-strip-pem (t, last, integer)
+@item gnus-treat-strip-pgp (t, last, integer)
+@item gnus-treat-strip-trailing-blank-lines (t, last, integer)
@item gnus-treat-translate
+@item gnus-treat-x-pgp-sig (head)
+@item gnus-treat-from-picon (head)
+@item gnus-treat-mail-picon (head)
+@item gnus-treat-newsgroups-picon (head)
+@item gnus-treat-unfold-headers (head)
+@item gnus-treat-fold-newsgroups (head)
+@item gnus-treat-body-boundary (head)
@end table
@vindex gnus-part-display-hook
@code{gnus-part-display-hook}. The functions are called narrowed to the
part, and you can do anything you like, pretty much. There is no
information that you have to keep in the buffer---you can change
-everything.
+everything.
@node Article Keymap
extensions:
@table @samp
+
@item w
The @dfn{wash status} of the article. This is a short string with one
character for each possible article wash operation that may have been
-performed.
+performed. The characters and their meaning:
+
+@table @samp
+
+@item c
+Displayed when cited text may be hidden in the article buffer.
+
+@item h
+Displayed when headers are hidden in the article buffer.
+
+@item p
+Displayed when article is digitally signed or encrypted, and Gnus has
+hidden the security headers. (N.B. does not tell anything about
+security status, i.e. good or bad signature.)
+
+@item s
+Displayed when the signature has been hidden in the Article buffer.
+
+@item o
+Displayed when Gnus has treated overstrike characters in the article buffer.
+
+@item e
+Displayed when Gnus has treated emphasised strings in the article buffer.
+
+@end table
+
@item m
The number of @sc{mime} parts in the article.
+
@end table
@vindex gnus-break-pages
on your setup (@pxref{Posting Server}).
@menu
-* Mail:: Mailing and replying.
-* Posting Server:: What server should you post via?
-* Mail and Post:: Mailing and posting at the same time.
-* Archived Messages:: Where Gnus stores the messages you've sent.
-* Posting Styles:: An easier way to specify who you are.
-* Drafts:: Postponing messages and rejected messages.
-* Rejected Articles:: What happens if the server doesn't like your article?
-* Using GPG:: How to use GPG and MML to sign and encrypt messages
+* Mail:: Mailing and replying.
+* Posting Server:: What server should you post via?
+* Mail and Post:: Mailing and posting at the same time.
+* Archived Messages:: Where Gnus stores the messages you've sent.
+* Posting Styles:: An easier way to specify who you are.
+* Drafts:: Postponing messages and rejected messages.
+* Rejected Articles:: What happens if the server doesn't like your article?
+* Using GPG:: How to use GPG and MML to sign and encrypt messages
@end menu
Also see @pxref{Canceling and Superseding} for information on how to
Now, if you've done this, and then this server rejects your article, or
this server is down, what do you do then? To override this variable you
can use a non-zero prefix to the @kbd{C-c C-c} command to force using
-the ``current'' server, to get back the default behaviour, for posting.
+the ``current'' server, to get back the default behavior, for posting.
If you give a zero prefix (i.e., @kbd{C-u 0 C-c C-c}) to that command,
Gnus will prompt you for what method to use for posting.
for posting.
Finally, if you want to always post using the native select method,
-you can set this variable to @code{nil}.
+you can set this variable to @code{native}.
@node Mail and Post
This variable can be used to do the following:
@itemize @bullet
-@item a string
+@item
+a string
Messages will be saved in that group.
Note that you can include a select method in the group name, then the
messages are stored in @samp{nnfolder+archive:foo}, but if you use the
value @code{"nnml:foo"}, then outgoing messages will be stored in
@samp{nnml:foo}.
-@item a list of strings
+@item
+a list of strings
Messages will be saved in all those groups.
-@item an alist of regexps, functions and forms
+@item
+an alist of regexps, functions and forms
When a key ``matches'', the result is used.
-@item @code{nil}
+@item
+@code{nil}
No message archiving will take place. This is the default.
@end itemize
(concat "mail." (format-time-string "%Y-%m")))))
@end lisp
-(XEmacs 19.13 doesn't have @code{format-time-string}, so you'll have to
-use a different value for @code{gnus-message-archive-group} there.)
+@c (XEmacs 19.13 doesn't have @code{format-time-string}, so you'll have to
+@c use a different value for @code{gnus-message-archive-group} there.)
Now, when you send a message off, it will be stored in the appropriate
group. (If you want to disable storing for just one particular message,
@lisp
(require 'gpg)
(setq mml2015-use 'gpg)
+(setq mml1991-use 'gpg)
(setq gpg-temp-directory (expand-file-name "~/.gnupg/tmp"))
@end lisp
The @code{gpg-temp-directory} need to point to a directory with permissions set
to 700, for your own safety.
-If you want to benefit of PGP2.6 compatibility, you might create a script named
-@file{gpg-2comp} with these instructions:
-
-@code{
-#!/bin/sh
-exec gpg --rfc1991 "$@@"
-}
-
-If you don't want to use such compatibility, you can add the following line to
-your @file{~/.emacs} or @file{~/.gnus}:
-
-@lisp
-(setq gpg-command-default-alist (quote ((gpg . "gpg") (gpg-2comp . "gpg"))))
-@end lisp
-
To sign or encrypt your message you may choose to use the MML Security
-menu or @kbd{C-c C-m s p} to sign your message using PGP/MIME, @kbd{C-c
-C-m s s} to sign your message using S/MIME. There's also @kbd{C-c C-m c
-p} to encrypt your message with PGP/MIME and @kbd{C-c C-m c s} to
-encrypt using S/MIME.
+menu or @kbd{C-c C-m s p} to sign your message using PGP/MIME,
+@kbd{C-c C-m s s} to sign your message using S/MIME. There's also
+@kbd{C-c C-m c p} to encrypt your message with PGP/MIME and @kbd{C-c
+C-m c s} to encrypt using S/MIME. @xref{Security, ,Security, message,
+The Message Manual}.
Gnus will ask for your passphrase and then it will send your message, if
you've typed it correctly.
A foreign group (or any group, really) is specified by a @dfn{name} and
a @dfn{select method}. To take the latter first, a select method is a
-list where the first element says what backend to use (e.g. @code{nntp},
+list where the first element says what back end to use (e.g. @code{nntp},
@code{nnspool}, @code{nnml}) and the second element is the @dfn{server
name}. There may be additional elements in the select method, where the
-value may have special meaning for the backend in question.
+value may have special meaning for the back end in question.
One could say that a select method defines a @dfn{virtual server}---so
we do just that (@pxref{Server Buffer}).
-The @dfn{name} of the group is the name the backend will recognize the
+The @dfn{name} of the group is the name the back end will recognize the
group as.
For instance, the group @samp{soc.motss} on the @sc{nntp} server
@samp{some.where.edu} will have the name @samp{soc.motss} and select
method @code{(nntp "some.where.edu")}. Gnus will call this group
@samp{nntp+some.where.edu:soc.motss}, even though the @code{nntp}
-backend just knows this group as @samp{soc.motss}.
+back end just knows this group as @samp{soc.motss}.
The different methods all have their peculiarities, of course.
@menu
-* Server Buffer:: Making and editing virtual servers.
-* Getting News:: Reading USENET news with Gnus.
-* Getting Mail:: Reading your personal mail with Gnus.
-* Browsing the Web:: Getting messages from a plethora of Web sources.
-* Other Sources:: Reading directories, files, SOUP packets.
-* Combined Groups:: Combining groups into one group.
-* Gnus Unplugged:: Reading news and mail offline.
+* Server Buffer:: Making and editing virtual servers.
+* Getting News:: Reading USENET news with Gnus.
+* Getting Mail:: Reading your personal mail with Gnus.
+* Browsing the Web:: Getting messages from a plethora of Web sources.
+* IMAP:: Using Gnus as a @sc{imap} client.
+* Other Sources:: Reading directories, files, SOUP packets.
+* Combined Groups:: Combining groups into one group.
+* Gnus Unplugged:: Reading news and mail offline.
@end menu
Traditionally, a @dfn{server} is a machine or a piece of software that
one connects to, and then requests information from. Gnus does not
connect directly to any real servers, but does all transactions through
-one backend or other. But that's just putting one layer more between
+one back end or other. But that's just putting one layer more between
the actual media and Gnus, so we might just as well say that each
-backend represents a virtual server.
+back end represents a virtual server.
-For instance, the @code{nntp} backend may be used to connect to several
+For instance, the @code{nntp} back end may be used to connect to several
different actual @sc{nntp} servers, or, perhaps, to many different ports
-on the same actual @sc{nntp} server. You tell Gnus which backend to
+on the same actual @sc{nntp} server. You tell Gnus which back end to
use, and what parameters to set by specifying a @dfn{select method}.
These select method specifications can sometimes become quite
(@code{gnus-group-enter-server-mode}) command in the group buffer.
@menu
-* Server Buffer Format:: You can customize the look of this buffer.
-* Server Commands:: Commands to manipulate servers.
-* Example Methods:: Examples server specifications.
-* Creating a Virtual Server:: An example session.
-* Server Variables:: Which variables to set.
-* Servers and Methods:: You can use server names as select methods.
-* Unavailable Servers:: Some servers you try to contact may be down.
+* Server Buffer Format:: You can customize the look of this buffer.
+* Server Commands:: Commands to manipulate servers.
+* Example Methods:: Examples server specifications.
+* Creating a Virtual Server:: An example session.
+* Server Variables:: Which variables to set.
+* Servers and Methods:: You can use server names as select methods.
+* Unavailable Servers:: Some servers you try to contact may be down.
@end menu
@vindex gnus-server-mode-hook
@table @samp
@item h
-How the news is fetched---the backend name.
+How the news is fetched---the back end name.
@item n
The name of this server.
@findex gnus-server-regenerate-server
Request that the server regenerate all its data structures
(@code{gnus-server-regenerate-server}). This can be useful if you have
-a mail backend that has gotten out of sync.
+a mail back end that has gotten out of sync.
@end table
@end lisp
As you can see, the first element in a select method is the name of the
-backend, and the second is the @dfn{address}, or @dfn{name}, if you
+back end, and the second is the @dfn{address}, or @dfn{name}, if you
will.
After these two elements, there may be an arbitrary number of
(nntp "news.funet.fi" (nntp-port-number 15))
@end lisp
-You should read the documentation to each backend to find out what
+You should read the documentation to each back end to find out what
variables are relevant, but here's an @code{nnmh} example:
-@code{nnmh} is a mail backend that reads a spool-like structure. Say
+@code{nnmh} is a mail back end that reads a spool-like structure. Say
you have two structures that you wish to access: One is your private
mail spool, and the other is a public one. Here's the possible spec for
your private mail:
@lisp
(nntp "firewall"
- (nntp-address "the.firewall.machine")
- (nntp-open-connection-function nntp-open-rlogin)
- (nntp-end-of-line "\n")
- (nntp-rlogin-parameters
- ("telnet" "the.real.nntp.host" "nntp")))
+ (nntp-open-connection-function nntp-open-via-rlogin-and-telnet)
+ (nntp-via-address "the.firewall.machine")
+ (nntp-address "the.real.nntp.host")
+ (nntp-end-of-line "\n"))
@end lisp
If you want to use the wonderful @code{ssh} program to provide a
-compressed connection over the modem line, you could create a virtual
-server that would look something like this:
+compressed connection over the modem line, you could add the following
+configuration to the example above:
+
+@lisp
+ (nntp-via-rlogin-command "ssh")
+@end lisp
+
+If you're behind a firewall, but have direct access to the outside world
+through a wrapper command like "runsocks", you could open a socksified
+telnet connection to the news server as follows:
@lisp
-(nntp "news"
- (nntp-address "copper.uio.no")
- (nntp-rlogin-program "ssh")
- (nntp-open-connection-function nntp-open-rlogin)
- (nntp-end-of-line "\n")
- (nntp-rlogin-parameters
- ("telnet" "news.uio.no" "nntp")))
+(nntp "outside"
+ (nntp-pre-command "runsocks")
+ (nntp-open-connection-function nntp-open-via-telnet)
+ (nntp-address "the.news.server")
+ (nntp-end-of-line "\n"))
@end lisp
This means that you have to have set up @code{ssh-agent} correctly to
@node Server Variables
@subsection Server Variables
-One sticky point when defining variables (both on backends and in Emacs
+One sticky point when defining variables (both on back ends and in Emacs
in general) is that some variables are typically initialized from other
variables when the definition of the variables is being loaded. If you
change the "base" variable after the variables have been loaded, you
new virtual @code{nnml} server, it will @emph{not} suffice to set just
@code{nnml-directory}---you have to explicitly set all the file
variables to be what you want them to be. For a complete list of
-variables for each backend, see each backend's section later in this
+variables for each back end, see each back end's section later in this
manual, but here's an example @code{nnml} definition:
@lisp
@node Getting News
@section Getting News
@cindex reading news
-@cindex news backends
+@cindex news back ends
A newsreader is normally used for reading news. Gnus currently provides
only two methods of getting news---it can read from an @sc{nntp} server,
or it can read from a local spool.
@menu
-* NNTP:: Reading news from an @sc{nntp} server.
-* News Spool:: Reading news from the local spool.
+* NNTP:: Reading news from an @sc{nntp} server.
+* News Spool:: Reading news from the local spool.
@end menu
The file contains one or more line, each of which define one server.
@item
-Each line may contain an arbitrary number of token/value pairs.
+Each line may contain an arbitrary number of token/value pairs.
The valid tokens include @samp{machine}, @samp{login}, @samp{password},
@samp{default}. In addition Gnus introduces two new tokens, not present
@lisp
'(("nntpd 1\\.5\\.11t"
- (remove-hook 'nntp-server-opened-hook 'nntp-send-mode-reader)))
+ (remove-hook 'nntp-server-opened-hook
+ 'nntp-send-mode-reader)))
@end lisp
This ensures that Gnus doesn't send the @code{MODE READER} command to
@item nntp-maximum-request
@vindex nntp-maximum-request
-If the @sc{nntp} server doesn't support @sc{nov} headers, this backend
+If the @sc{nntp} server doesn't support @sc{nov} headers, this back end
will collect headers by sending a series of @code{head} commands. To
-speed things up, the backend sends lots of these commands without
+speed things up, the back end sends lots of these commands without
waiting for reply, and then reads all the replies. This is controlled
by the @code{nntp-maximum-request} variable, and is 400 by default. If
your network is buggy, you should set this to 1.
responding properly, or being too loaded to reply within reasonable
time. This is can lead to awkward problems, which can be helped
somewhat by setting @code{nntp-connection-timeout}. This is an integer
-that says how many seconds the @code{nntp} backend should wait for a
+that says how many seconds the @code{nntp} back end should wait for a
connection before giving up. If it is @code{nil}, which is the default,
no timeouts are done.
This hook is run as the last step when connecting to an @sc{nntp}
server.
-@findex nntp-open-rlogin
-@findex nntp-open-telnet
-@findex nntp-open-network-stream
-@item nntp-open-connection-function
-@vindex nntp-open-connection-function
-This function is used to connect to the remote system. Four pre-made
-functions are supplied:
-
-@table @code
-@item nntp-open-network-stream
-This is the default, and simply connects to some port or other on the
-remote system.
-
-@item nntp-open-rlogin
-Does an @samp{rlogin} on the
-remote system, and then does a @samp{telnet} to the @sc{nntp} server
-available there.
+@item nntp-buggy-select
+@vindex nntp-buggy-select
+Set this to non-@code{nil} if your select routine is buggy.
-@code{nntp-open-rlogin}-related variables:
+@item nntp-nov-is-evil
+@vindex nntp-nov-is-evil
+If the @sc{nntp} server does not support @sc{nov}, you could set this
+variable to @code{t}, but @code{nntp} usually checks automatically whether @sc{nov}
+can be used.
-@table @code
+@item nntp-xover-commands
+@vindex nntp-xover-commands
+@cindex nov
+@cindex XOVER
+List of strings used as commands to fetch @sc{nov} lines from a
+server. The default value of this variable is @code{("XOVER"
+"XOVERVIEW")}.
-@item nntp-rlogin-program
-@vindex nntp-rlogin-program
-Program used to log in on remote machines. The default is @samp{rsh},
-but @samp{ssh} is a popular alternative.
+@item nntp-nov-gap
+@vindex nntp-nov-gap
+@code{nntp} normally sends just one big request for @sc{nov} lines to
+the server. The server responds with one huge list of lines. However,
+if you have read articles 2-5000 in the group, and only want to read
+article 1 and 5001, that means that @code{nntp} will fetch 4999 @sc{nov}
+lines that you will not need. This variable says how
+big a gap between two consecutive articles is allowed to be before the
+@code{XOVER} request is split into several request. Note that if your
+network is fast, setting this variable to a really small number means
+that fetching will probably be slower. If this variable is @code{nil},
+@code{nntp} will never split requests. The default is 5.
-@item nntp-rlogin-parameters
-@vindex nntp-rlogin-parameters
-This list will be used as the parameter list given to @code{rsh}.
-
-@item nntp-rlogin-user-name
-@vindex nntp-rlogin-user-name
-User name on the remote system.
-
-@end table
+@item nntp-prepare-server-hook
+@vindex nntp-prepare-server-hook
+A hook run before attempting to connect to an @sc{nntp} server.
-@item nntp-open-telnet
-Does a @samp{telnet} to the remote system and then another @samp{telnet}
-to get to the @sc{nntp} server.
+@item nntp-warn-about-losing-connection
+@vindex nntp-warn-about-losing-connection
+If this variable is non-@code{nil}, some noise will be made when a
+server closes connection.
-@code{nntp-open-telnet}-related variables:
+@item nntp-record-commands
+@vindex nntp-record-commands
+If non-@code{nil}, @code{nntp} will log all commands it sends to the
+@sc{nntp} server (along with a timestamp) in the @samp{*nntp-log*}
+buffer. This is useful if you are debugging a Gnus/@sc{nntp} connection
+that doesn't seem to work.
-@table @code
-@item nntp-telnet-command
-@vindex nntp-telnet-command
-Command used to start @code{telnet}.
+@item nntp-open-connection-function
+@vindex nntp-open-connection-function
+It is possible to customize how the connection to the nntp server will
+be opened. If you specify an @code{nntp-open-connection-function}
+parameter, Gnus will use that function to establish the connection.
+Five pre-made functions are supplied. These functions can be grouped in
+two categories: direct connection functions (three pre-made), and
+indirect ones (two pre-made).
+
+@item nntp-prepare-post-hook
+@vindex nntp-prepare-post-hook
+A hook run just before posting an article. If there is no
+@code{Message-ID} header in the article and the news server provides the
+recommended ID, it will be added to the article before running this
+hook. It is useful to make @code{Cancel-Lock} headers even if you
+inhibit Gnus to add a @code{Message-ID} header, you could say:
-@item nntp-telnet-switches
-@vindex nntp-telnet-switches
-List of strings to be used as the switches to the @code{telnet} command.
+@lisp
+(add-hook 'nntp-prepare-post-hook 'canlock-insert-header)
+@end lisp
-@item nntp-telnet-user-name
-@vindex nntp-telnet-user-name
-User name for log in on the remote system.
+Note that not all servers support the recommended ID. This works for
+INN versions 2.3.0 and later, for instance.
+@end table
-@item nntp-telnet-passwd
-@vindex nntp-telnet-passwd
-Password to use when logging in.
+@menu
+* Direct Functions:: Connecting directly to the server.
+* Indirect Functions:: Connecting indirectly to the server.
+* Common Variables:: Understood by several connection functions.
+@end menu
-@item nntp-telnet-parameters
-@vindex nntp-telnet-parameters
-A list of strings executed as a command after logging in
-via @code{telnet}.
-@item nntp-telnet-shell-prompt
-@vindex nntp-telnet-shell-prompt
-Regexp matching the shell prompt on the remote machine. The default is
-@samp{bash\\|\$ *\r?$\\|> *\r?}.
+@node Direct Functions
+@subsubsection Direct Functions
+@cindex direct connection functions
-@item nntp-open-telnet-envuser
-@vindex nntp-open-telnet-envuser
-If non-@code{nil}, the @code{telnet} session (client and server both)
-will support the @code{ENVIRON} option and not prompt for login name.
-This works for Solaris @code{telnet}, for instance.
+These functions are called direct because they open a direct connection
+between your machine and the @sc{nntp} server. The behavior of these
+functions is also affected by commonly understood variables
+(@pxref{Common Variables}).
-@end table
+@table @code
+@findex nntp-open-network-stream
+@item nntp-open-network-stream
+This is the default, and simply connects to some port or other on the
+remote system.
@findex nntp-open-ssl-stream
@item nntp-open-ssl-stream
-Opens a connection to a server over a @dfn{secure} channel. To use this
-you must have SSLay installed
-(@uref{ftp://ftp.psy.uq.oz.au/pub/Crypto/SSL}, and you also need
-@file{ssl.el} (from the W3 distribution, for instance). You then
+Opens a connection to a server over a @dfn{secure} channel. To use
+this you must have OpenSSL (@uref{http://www.openssl.org}) or SSLeay
+installed (@uref{ftp://ftp.psy.uq.oz.au/pub/Crypto/SSL}, and you also
+need @file{ssl.el} (from the W3 distribution, for instance). You then
define a server as follows:
@lisp
(nntp-address "snews.bar.com"))
@end lisp
+@findex nntp-open-telnet-stream
+@item nntp-open-telnet-stream
+Opens a connection to an @sc{nntp} server by simply @samp{telnet}'ing
+it. You might wonder why this function exists, since we have the
+default @code{nntp-open-network-stream} which would do the job. (One
+of) the reason(s) is that if you are behind a firewall but have direct
+connections to the outside world thanks to a command wrapper like
+@code{runsocks}, you can use it like this:
+
+@lisp
+(nntp "socksified"
+ (nntp-pre-command "runsocks")
+ (nntp-open-connection-function nntp-open-telnet-stream)
+ (nntp-address "the.news.server"))
+@end lisp
+
+With the default method, you would need to wrap your whole Emacs
+session, which is not a good idea.
@end table
-@item nntp-end-of-line
-@vindex nntp-end-of-line
-String to use as end-of-line marker when talking to the @sc{nntp}
-server. This is @samp{\r\n} by default, but should be @samp{\n} when
-using @code{rlogin} to talk to the server.
-@item nntp-rlogin-user-name
-@vindex nntp-rlogin-user-name
-User name on the remote system when using the @code{rlogin} connect
-function.
+@node Indirect Functions
+@subsubsection Indirect Functions
+@cindex indirect connection functions
-@item nntp-address
-@vindex nntp-address
-The address of the remote system running the @sc{nntp} server.
+These functions are called indirect because they connect to an
+intermediate host before actually connecting to the @sc{nntp} server.
+All of these functions and related variables are also said to belong to
+the "via" family of connection: they're all prefixed with "via" to make
+things cleaner. The behavior of these functions is also affected by
+commonly understood variables (@pxref{Common Variables}).
-@item nntp-port-number
-@vindex nntp-port-number
-Port number to connect to when using the @code{nntp-open-network-stream}
-connect function.
+@table @code
+@item nntp-open-via-rlogin-and-telnet
+@findex nntp-open-via-rlogin-and-telnet
+Does an @samp{rlogin} on a remote system, and then does a @samp{telnet}
+to the real @sc{nntp} server from there. This is useful for instance if
+you need to connect to a firewall machine first.
-@item nntp-buggy-select
-@vindex nntp-buggy-select
-Set this to non-@code{nil} if your select routine is buggy.
+@code{nntp-open-via-rlogin-and-telnet}-specific variables:
-@item nntp-nov-is-evil
-@vindex nntp-nov-is-evil
-If the @sc{nntp} server does not support @sc{nov}, you could set this
-variable to @code{t}, but @code{nntp} usually checks automatically whether @sc{nov}
-can be used.
+@table @code
+@item nntp-via-rlogin-command
+@vindex nntp-via-rlogin-command
+Command used to log in on the intermediate host. The default is
+@samp{rsh}, but @samp{ssh} is a popular alternative.
+@end table
-@item nntp-xover-commands
-@vindex nntp-xover-commands
-@cindex nov
-@cindex XOVER
-List of strings used as commands to fetch @sc{nov} lines from a
-server. The default value of this variable is @code{("XOVER"
-"XOVERVIEW")}.
+@item nntp-open-via-telnet-and-telnet
+@findex nntp-open-via-telnet-and-telnet
+Does essentially the same, but uses @samp{telnet} instead of
+@samp{rlogin} to connect to the intermediate host.
-@item nntp-nov-gap
-@vindex nntp-nov-gap
-@code{nntp} normally sends just one big request for @sc{nov} lines to
-the server. The server responds with one huge list of lines. However,
-if you have read articles 2-5000 in the group, and only want to read
-article 1 and 5001, that means that @code{nntp} will fetch 4999 @sc{nov}
-lines that you will not need. This variable says how
-big a gap between two consecutive articles is allowed to be before the
-@code{XOVER} request is split into several request. Note that if your
-network is fast, setting this variable to a really small number means
-that fetching will probably be slower. If this variable is @code{nil},
-@code{nntp} will never split requests. The default is 5.
+@code{nntp-open-via-telnet-and-telnet}-specific variables:
-@item nntp-prepare-server-hook
-@vindex nntp-prepare-server-hook
-A hook run before attempting to connect to an @sc{nntp} server.
+@table @code
+@item nntp-via-telnet-command
+@vindex nntp-via-telnet-command
+Command used to @code{telnet} the intermediate host. The default is
+@samp{telnet}.
+
+@item nntp-via-telnet-switches
+@vindex nntp-via-telnet-switches
+List of strings to be used as the switches to the
+@code{nntp-via-telnet-command} command. The default is @samp{("-8")}.
+
+@item nntp-via-user-password
+@vindex nntp-via-user-password
+Password to use when logging in on the intermediate host.
+
+@item nntp-via-envuser
+@vindex nntp-via-envuser
+If non-@code{nil}, the intermediate @code{telnet} session (client and
+server both) will support the @code{ENVIRON} option and not prompt for
+login name. This works for Solaris @code{telnet}, for instance.
+
+@item nntp-via-shell-prompt
+@vindex nntp-via-shell-prompt
+Regexp matching the shell prompt on the intermediate host. The default
+is @samp{bash\\|\$ *\r?$\\|> *\r?}.
-@item nntp-warn-about-losing-connection
-@vindex nntp-warn-about-losing-connection
-If this variable is non-@code{nil}, some noise will be made when a
-server closes connection.
+@end table
-@item nntp-record-commands
-@vindex nntp-record-commands
-If non-@code{nil}, @code{nntp} will log all commands it sends to the
-@sc{nntp} server (along with a timestamp) in the @samp{*nntp-log*}
-buffer. This is useful if you are debugging a Gnus/@sc{nntp} connection
-that doesn't seem to work.
+@end table
+
+
+Here are some additional variables that are understood by all the above
+functions:
+
+@table @code
+
+@item nntp-via-user-name
+@vindex nntp-via-user-name
+User name to use when connecting to the intermediate host.
+
+@item nntp-via-address
+@vindex nntp-via-address
+Address of the intermediate host to connect to.
+
+@end table
+
+
+@node Common Variables
+@subsubsection Common Variables
+
+The following variables affect the behavior of all, or several of the
+pre-made connection functions. When not specified, all functions are
+affected.
+
+@table @code
+
+@item nntp-pre-command
+@vindex nntp-pre-command
+A command wrapper to use when connecting through a non native connection
+function (all except @code{nntp-open-network-stream} and
+@code{nntp-open-ssl-stream}. This is where you would put a @samp{SOCKS}
+wrapper for instance.
+
+@item nntp-address
+@vindex nntp-address
+The address of the @sc{nntp} server.
+
+@item nntp-port-number
+@vindex nntp-port-number
+Port number to connect to the @sc{nntp} server. The default is @samp{nntp}.
+
+@item nntp-end-of-line
+@vindex nntp-end-of-line
+String to use as end-of-line marker when talking to the @sc{nntp}
+server. This is @samp{\r\n} by default, but should be @samp{\n} when
+using a non native connection function.
+
+@item nntp-telnet-command
+@vindex nntp-telnet-command
+Command to use when connecting to the @sc{nntp} server through
+@samp{telnet}. This is NOT for an intermediate host. This is just for
+the real @sc{nntp} server. The default is @samp{telnet}.
+
+@item nntp-telnet-switches
+@vindex nntp-telnet-switches
+A list of switches to pass to @code{nntp-telnet-command}. The default
+is @samp{("-8")}.
@end table
course.
@menu
-* Mail in a Newsreader:: Important introductory notes.
-* Getting Started Reading Mail:: A simple cookbook example.
-* Splitting Mail:: How to create mail groups.
-* Mail Sources:: How to tell Gnus where to get mail from.
-* Mail Backend Variables:: Variables for customizing mail handling.
-* Fancy Mail Splitting:: Gnus can do hairy splitting of incoming mail.
-* Group Mail Splitting:: Use group customize to drive mail splitting.
-* Incorporating Old Mail:: What about the old mail you have?
-* Expiring Mail:: Getting rid of unwanted mail.
-* Washing Mail:: Removing gruft from the mail you get.
-* Duplicates:: Dealing with duplicated mail.
-* Not Reading Mail:: Using mail backends for reading other files.
-* Choosing a Mail Backend:: Gnus can read a variety of mail formats.
+* Mail in a Newsreader:: Important introductory notes.
+* Getting Started Reading Mail:: A simple cookbook example.
+* Splitting Mail:: How to create mail groups.
+* Mail Sources:: How to tell Gnus where to get mail from.
+* Mail Back End Variables:: Variables for customizing mail handling.
+* Fancy Mail Splitting:: Gnus can do hairy splitting of incoming mail.
+* Group Mail Splitting:: Use group customize to drive mail splitting.
+* Incorporating Old Mail:: What about the old mail you have?
+* Expiring Mail:: Getting rid of unwanted mail.
+* Washing Mail:: Removing gruft from the mail you get.
+* Duplicates:: Dealing with duplicated mail.
+* Not Reading Mail:: Using mail back ends for reading other files.
+* Choosing a Mail Back End:: Gnus can read a variety of mail formats.
+* Archiving Mail:: How to backup your mail.
@end menu
@node Mail in a Newsreader
@subsection Mail in a Newsreader
-If you are used to traditional mail readers, but have decided to switch
+If you are used to traditional mail readers, but have decided to switch
to reading mail with Gnus, you may find yourself experiencing something
of a culture shock.
-Gnus does not behave like traditional mail readers. If you want to make
+Gnus does not behave like traditional mail readers. If you want to make
it behave that way, you can, but it's an uphill battle.
Gnus, by default, handles all its groups using the same approach. This
deleted? How awful!
But, no, it means that old messages are @dfn{expired} according to some
-scheme or other. For news messages, the expire process is controlled by
+scheme or other. For news messages, the expire process is controlled by
the news administrator; for mail, the expire process is controlled by
you. The expire process for mail is covered in depth in @pxref{Expiring
Mail}.
@subsection Getting Started Reading Mail
It's quite easy to use Gnus to read your new mail. You just plonk the
-mail backend of your choice into @code{gnus-secondary-select-methods},
+mail back end of your choice into @code{gnus-secondary-select-methods},
and things will happen automatically.
For instance, if you want to use @code{nnml} (which is a "one file per
-mail" backend), you could put the following in your @file{.gnus} file:
+mail" back end), you could put the following in your @file{.gnus} file:
@lisp
-(setq gnus-secondary-select-methods
- '((nnml "private")))
+(setq gnus-secondary-select-methods '((nnml "")))
@end lisp
-Now, the next time you start Gnus, this backend will be queried for new
+Now, the next time you start Gnus, this back end will be queried for new
articles, and it will move all the messages in your spool file to its
directory, which is @code{~/Mail/} by default. The new group that will
be created (@samp{mail.misc}) will be subscribed, and you can read it
This should be sufficient for reading mail with Gnus. You might want to
give the other sections in this part of the manual a perusal, though.
-Especially @pxref{Choosing a Mail Backend} and @pxref{Expiring Mail}.
+Especially @pxref{Choosing a Mail Back End} and @pxref{Expiring Mail}.
@node Splitting Mail
message. The function should return a list of group names that it
thinks should carry this mail message.
-Note that the mail backends are free to maul the poor, innocent,
+Note that the mail back ends are free to maul the poor, innocent,
incoming headers all they want to. They all add @code{Lines} headers;
some add @code{X-Gnus-Group} headers; most rename the Unix mbox
@code{From<SPACE>} line to something else.
@vindex nnmail-crosspost
-The mail backends all support cross-posting. If several regexps match,
+The mail back ends all support cross-posting. If several regexps match,
the mail will be ``cross-posted'' to all those groups.
@code{nnmail-crosspost} says whether to use this mechanism or not. Note
that no articles are crossposted to the general (@samp{}) group.
can use the @kbd{M-x nnmail-split-history} command. If you wish to see
where re-spooling messages would put the messages, you can use
@code{gnus-summary-respool-trace} and related commands (@pxref{Mail
-Group Commands}).
+Group Commands}).
Gnus gives you all the opportunity you could possibly want for shooting
yourself in the foot. Let's say you create a group that will contain
instance.
@menu
-* Mail Source Specifiers:: How to specify what a mail source is.
-* Mail Source Customization:: Some variables that influence things.
-* Fetching Mail:: Using the mail source specifiers.
+* Mail Source Specifiers:: How to specify what a mail source is.
+* Mail Source Customization:: Some variables that influence things.
+* Fetching Mail:: Using the mail source specifiers.
@end menu
(file)
@end lisp
-If the mail spool file is not located on the local machine, it's best to
-use POP or @sc{imap} or the like to fetch the mail. You can not use ange-ftp
+If the mail spool file is not located on the local machine, it's best to
+use POP or @sc{imap} or the like to fetch the mail. You can not use ange-ftp
file names here---it has no way to lock the mail spool while moving the
mail.
@item directory
-Get mail from several files in a directory. This is typically used when
-you have procmail split the incoming mail into several files. Setting
-@code{nnmail-scan-directory-mail-source-once} to non-nil forces Gnus to
-scan the mail source only once. This is particularly useful if you want
-to scan mail groups at a specified level.
+Get mail from several files in a directory. This is typically used
+when you have procmail split the incoming mail into several files.
+That is, mail from the file @file{foo.bar.spool} will be put in the
+group @code{foo.bar}. (You can change the suffix to be used instead
+of @code{.spool}.) Setting
+@code{nnmail-scan-directory-mail-source-once} to non-nil forces Gnus
+to scan the mail source only once. This is particularly useful if you
+want to scan mail groups at a specified level.
Keywords:
Two example maildir mail sources:
@lisp
-(maildir :path "/home/user-name/Maildir/" :subdirs ("cur" "new"))
+(maildir :path "/home/user-name/Maildir/"
+ :subdirs ("cur" "new"))
@end lisp
@lisp
-(maildir :path "/user@@remotehost.org:~/Maildir/" :subdirs ("new"))
+(maildir :path "/user@@remotehost.org:~/Maildir/"
+ :subdirs ("new"))
@end lisp
@item imap
and fetches articles from a given @sc{imap} mailbox. @xref{IMAP}, for
more information.
+Note that for the Kerberos, GSSAPI, SSL/TLS and STARTTLS support you
+may need external programs and libraries, @xref{IMAP}.
+
Keywords:
@table @code
@item :port
The port number of the @sc{imap} server. The default is @samp{143}, or
-@samp{993} for SSL connections.
+@samp{993} for SSL/TLS connections.
@item :user
The user name to give to the @sc{imap} server. The default is the login
@item :stream
What stream to use for connecting to the server, this is one of the
symbols in @code{imap-stream-alist}. Right now, this means
-@samp{kerberos4}, @samp{ssl} or the default @samp{network}.
+@samp{gssapi}, @samp{kerberos4}, @samp{starttls}, @samp{ssl},
+@samp{shell} or the default @samp{network}.
@item :authentication
-Which authenticator to use for authenticating to the server, this is one
-of the symbols in @code{imap-authenticator-alist}. Right now, this
-means @samp{kerberos4}, @samp{cram-md5}, @samp{anonymous} or the default
-@samp{login}.
+Which authenticator to use for authenticating to the server, this is
+one of the symbols in @code{imap-authenticator-alist}. Right now,
+this means @samp{gssapi}, @samp{kerberos4}, @samp{digest-md5},
+@samp{cram-md5}, @samp{anonymous} or the default @samp{login}.
@item :program
When using the `shell' :stream, the contents of this variable is
An example @sc{imap} mail source:
@lisp
-(imap :server "mail.mycorp.com" :stream kerberos4 :fetchflag "\\Seen")
+(imap :server "mail.mycorp.com"
+ :stream kerberos4
+ :fetchflag "\\Seen")
@end lisp
@item webmail
An example webmail source:
@lisp
-(webmail :subtype 'hotmail :user "user-name" :password "secret")
+(webmail :subtype 'hotmail
+ :user "user-name"
+ :password "secret")
@end lisp
@end table
@lisp
(setq mail-sources
- '((directory :path "/home/pavel/.Spool/"
+ '((directory :path "/home/pavel/.Spool/"
:suffix ""
:plugged t)))
@end lisp
@vindex mail-source-default-file-modes
All new mail files will get this file mode. The default is 384.
+@item mail-source-movemail-program
+@vindex mail-source-movemail-program
+If non-nil, name of program for fetching new mail. If nil,
+@code{movemail} in @var{exec-directory}.
+
@end table
(@pxref{Mail Source Specifiers}).
If this variable (and the obsolescent @code{nnmail-spool-file}) is
-@code{nil}, the mail backends will never attempt to fetch mail by
+@code{nil}, the mail back ends will never attempt to fetch mail by
themselves.
If you want to fetch mail both from your local spool as well as a POP
@end lisp
-When you use a mail backend, Gnus will slurp all your mail from your
+When you use a mail back end, Gnus will slurp all your mail from your
inbox and plonk it down in your home directory. Gnus doesn't move any
-mail if you're not using a mail backend---you have to do a lot of magic
+mail if you're not using a mail back end---you have to do a lot of magic
invocations first. At the time when you have finished drawing the
pentagram, lightened the candles, and sacrificed the goat, you really
shouldn't be too surprised when Gnus moves your mail.
-@node Mail Backend Variables
-@subsection Mail Backend Variables
+@node Mail Back End Variables
+@subsection Mail Back End Variables
These variables are (for the most part) pertinent to all the various
-mail backends.
+mail back ends.
@table @code
@vindex nnmail-read-incoming-hook
@item nnmail-read-incoming-hook
-The mail backends all call this hook after reading new mail. You can
+The mail back ends all call this hook after reading new mail. You can
use this hook to notify any mail watch programs, if you want to.
@vindex nnmail-split-hook
default file modes the new mail files get:
@lisp
-(add-hook 'gnus-pre-get-new-mail-hook
+(add-hook 'nnmail-pre-get-new-mail-hook
(lambda () (set-default-file-modes 511)))
-(add-hook 'gnus-post-get-new-mail-hook
+(add-hook 'nnmail-post-get-new-mail-hook
(lambda () (set-default-file-modes 551)))
@end lisp
@item nnmail-use-long-file-names
@vindex nnmail-use-long-file-names
-If non-@code{nil}, the mail backends will use long file and directory
+If non-@code{nil}, the mail back ends will use long file and directory
names. Groups like @samp{mail.misc} will end up in directories
-(assuming use of @code{nnml} backend) or files (assuming use of
-@code{nnfolder} backend) like @file{mail.misc}. If it is @code{nil},
+(assuming use of @code{nnml} back end) or files (assuming use of
+@code{nnfolder} back end) like @file{mail.misc}. If it is @code{nil},
the same group will end up in @file{mail/misc}.
@item nnmail-delete-file-function
@item nnmail-cache-accepted-message-ids
@vindex nnmail-cache-accepted-message-ids
If non-@code{nil}, put the @code{Message-ID}s of articles imported into
-the backend (via @code{Gcc}, for instance) into the mail duplication
+the back end (via @code{Gcc}, for instance) into the mail duplication
discovery cache. The default is @code{nil}.
@end table
(any "procmail@@informatik\\.rwth-aachen\\.de" "procmail.list")
(any "SmartList@@informatik\\.rwth-aachen\\.de" "SmartList.list")
;; Both lists below have the same suffix, so prevent
- ;; cross-posting to mkpkg.list of messages posted only to
+ ;; cross-posting to mkpkg.list of messages posted only to
;; the bugs- list, but allow cross-posting when the
;; message was really cross-posted.
(any "bugs-mypackage@@somewhere" "mypkg.bugs")
@item
@code{junk}: If the split is the symbol @code{junk}, then don't save
-this message. Use with extreme caution.
+(i.e., delete) this message. Use with extreme caution.
@item
@code{(: @var{function} @var{arg1} @var{arg2} @dots{})}: If the split is
messages into the right group. With this function, you only have to do
it once per thread.
-To use this feature, you have to set @code{nnmail-treat-duplicates} to a
-non-nil value. And then you can include
-@code{nnmail-split-fancy-with-parent} using the colon feature, like so:
+To use this feature, you have to set @code{nnmail-treat-duplicates} and
+@code{nnmail-cache-accepted-message-ids} to a non-nil value. And then
+you can include @code{nnmail-split-fancy-with-parent} using the colon
+feature, like so:
@lisp
(setq nnmail-split-fancy
'(| (: nnmail-split-fancy-with-parent)
@code{nnmail-split-fancy-with-parent} then looks at the References (and
In-Reply-To) header of each message to split and searches the file
specified by @code{nnmail-message-id-cache-file} for the message ids.
-When it has found a parent, it returns the corresponding group name. It
-is recommended that you set @code{nnmail-message-id-cache-length} to a
-somewhat higher number than the default so that the message ids are
-still in the cache. (A value of 5000 appears to create a file some 300
-kBytes in size.)
+When it has found a parent, it returns the corresponding group name
+unless the group name matches the regexp
+@code{nnmail-split-fancy-with-parent-ignore-groups}. It is recommended
+that you set @code{nnmail-message-id-cache-length} to a somewhat higher
+number than the default so that the message ids are still in the cache.
+(A value of 5000 appears to create a file some 300 kBytes in size.)
@vindex nnmail-cache-accepted-message-ids
When @code{nnmail-cache-accepted-message-ids} is non-@code{nil}, Gnus
also records the message ids of moved articles, so that the followup
@node Incorporating Old Mail
@subsection Incorporating Old Mail
+@cindex incorporating old mail
+@cindex import old mail
Most people have lots of old mail stored in various file formats. If
you have set up Gnus to read mail using one of the spiffy Gnus mail
-backends, you'll probably wish to have that old mail incorporated into
+back ends, you'll probably wish to have that old mail incorporated into
your mail groups.
Doing so can be quite easy.
sure that all the mail has ended up where it should be.
Respooling is also a handy thing to do if you're switching from one mail
-backend to another. Just respool all the mail in the old mail groups
-using the new mail backend.
+back end to another. Just respool all the mail in the old mail groups
+using the new mail back end.
@node Expiring Mail
Note that making a group auto-expirable doesn't mean that all read
articles are expired---only the articles marked as expirable
will be expired. Also note that using the @kbd{d} command won't make
-groups expirable---only semi-automatic marking of articles as read will
+articles expirable---only semi-automatic marking of articles as read will
mark the articles as expirable in auto-expirable groups.
Let's say you subscribe to a couple of mailing lists, and you want the
@vindex nnmail-expiry-target
The normal action taken when expiring articles is to delete them.
-However, in some circumstances it might make more sense to move them to
-other groups instead of deleting them. The variable @code{nnmail-expiry-target}
-(and the @code{expiry-target} group parameter) controls this. The
-variable supplies a default value for all groups, which can be
-overridden for specific groups by the group parameter.
-default value is @code{delete}, but this can also be a string (which
-should be the name of the group the message should be moved to), or a
-function (which will be called in a buffer narrowed to the message in
-question, and with the name of the group being moved from as its
-parameter) which should return a target -- either a group name or
-@code{delete}.
+However, in some circumstances it might make more sense to move them
+to other groups instead of deleting them. The variable
+@code{nnmail-expiry-target} (and the @code{expiry-target} group
+parameter) controls this. The variable supplies a default value for
+all groups, which can be overridden for specific groups by the group
+parameter. default value is @code{delete}, but this can also be a
+string (which should be the name of the group the message should be
+moved to), or a function (which will be called in a buffer narrowed to
+the message in question, and with the name of the group being moved
+from as its parameter) which should return a target -- either a group
+name or @code{delete}.
Here's an example for specifying a group name:
@lisp
(setq nnmail-expiry-target "nnml:expired")
@end lisp
+@findex nnmail-fancy-expiry-target
+@vindex nnmail-fancy-expiry-targets
+Gnus provides a function @code{nnmail-fancy-expiry-target} which will
+expire mail to groups according to the variable
+@code{nnmail-fancy-expiry-targets}. Here's an example:
+
+@lisp
+ (setq nnmail-expiry-target 'nnmail-fancy-expiry-target
+ nnmail-fancy-expiry-targets
+ '((to-from "boss" "nnfolder:Work")
+ ("subject" "IMPORTANT" "nnfolder:IMPORTANT.%Y.%b")
+ ("from" ".*" "nnfolder:Archive-%Y")))
+@end lisp
+
+With this setup, any mail that has @code{IMPORTANT} in its Subject
+header and was sent in the year @code{YYYY} and month @code{MMM}, will
+get expired to the group @code{nnfolder:IMPORTANT.YYYY.MMM}. If its
+From or To header contains the string @code{boss}, it will get expired
+to @code{nnfolder:Work}. All other mail will get expired to
+@code{nnfolder:Archive-YYYY}.
@vindex nnmail-keep-last-article
If @code{nnmail-keep-last-article} is non-@code{nil}, Gnus will never
@lisp
(setq nnmail-split-fancy
'(| ;; Messages duplicates go to a separate group.
- ("gnus-warning" "duplication of message" "duplicate")
+ ("gnus-warning" "duplicat\\(e\\|ion\\) of message" "duplicate")
;; Message from daemons, postmaster, and the like to another.
(any mail "mail.misc")
;; Other rules.
Or something like:
@lisp
(setq nnmail-split-methods
- '(("duplicates" "^Gnus-Warning:")
+ '(("duplicates" "^Gnus-Warning:.*duplicate")
;; Other rules.
[...]))
@end lisp
@node Not Reading Mail
@subsection Not Reading Mail
-If you start using any of the mail backends, they have the annoying
+If you start using any of the mail back ends, they have the annoying
habit of assuming that you want to read mail with them. This might not
be unreasonable, but it might not be what you want.
If you set @code{mail-sources} and @code{nnmail-spool-file} to
-@code{nil}, none of the backends will ever attempt to read incoming
+@code{nil}, none of the back ends will ever attempt to read incoming
mail, which should help.
@vindex nnbabyl-get-new-mail
@vindex nnfolder-get-new-mail
This might be too much, if, for instance, you are reading mail quite
happily with @code{nnml} and just want to peek at some old @sc{rmail}
-file you have stashed away with @code{nnbabyl}. All backends have
-variables called backend-@code{get-new-mail}. If you want to disable
+file you have stashed away with @code{nnbabyl}. All back ends have
+variables called back-end-@code{get-new-mail}. If you want to disable
the @code{nnbabyl} mail reading, you edit the virtual server for the
group to have a setting where @code{nnbabyl-get-new-mail} to @code{nil}.
-All the mail backends will call @code{nn}*@code{-prepare-save-mail-hook}
+All the mail back ends will call @code{nn}*@code{-prepare-save-mail-hook}
narrowed to the article to be saved before saving it when reading
incoming mail.
-@node Choosing a Mail Backend
-@subsection Choosing a Mail Backend
+@node Choosing a Mail Back End
+@subsection Choosing a Mail Back End
Gnus will read the mail spool when you activate a mail group. The mail
file is first copied to your home directory. What happens after that
depends on what format you want to store your mail in.
-There are five different mail backends in the standard Gnus, and more
-backends are available separately. The mail backend most people use
+There are five different mail back ends in the standard Gnus, and more
+back ends are available separately. The mail back end most people use
(because it is the fastest and most flexible) is @code{nnml}
(@pxref{Mail Spool}).
* Unix Mail Box:: Using the (quite) standard Un*x mbox.
* Rmail Babyl:: Emacs programs use the rmail babyl format.
* Mail Spool:: Store your mail in a private spool?
-* MH Spool:: An mhspool-like backend.
+* MH Spool:: An mhspool-like back end.
* Mail Folders:: Having one file for each group.
-* Comparing Mail Backends:: An in-depth looks at pros and cons.
+* Comparing Mail Back Ends:: An in-depth looks at pros and cons.
@end menu
@vindex nnmbox-active-file
@vindex nnmbox-mbox-file
-The @dfn{nnmbox} backend will use the standard Un*x mbox file to store
+The @dfn{nnmbox} back end will use the standard Un*x mbox file to store
mail. @code{nnmbox} will add extra headers to each mail article to say
which group it belongs in.
@table @code
@item nnmbox-mbox-file
@vindex nnmbox-mbox-file
-The name of the mail box in the user's home directory.
+The name of the mail box in the user's home directory. Default is
+@file{~/mbox}.
@item nnmbox-active-file
@vindex nnmbox-active-file
-The name of the active file for the mail box.
+The name of the active file for the mail box. Default is
+@file{~/.mbox-active}.
@item nnmbox-get-new-mail
@vindex nnmbox-get-new-mail
If non-@code{nil}, @code{nnmbox} will read incoming mail and split it
-into groups.
+into groups. Default is @code{t}.
@end table
@vindex nnbabyl-active-file
@vindex nnbabyl-mbox-file
-The @dfn{nnbabyl} backend will use a babyl mail box (aka. @dfn{rmail
+The @dfn{nnbabyl} back end will use a babyl mail box (aka. @dfn{rmail
mbox}) to store mail. @code{nnbabyl} will add extra headers to each
mail article to say which group it belongs in.
@table @code
@item nnbabyl-mbox-file
@vindex nnbabyl-mbox-file
-The name of the rmail mbox file.
+The name of the rmail mbox file. The default is @file{~/RMAIL}
@item nnbabyl-active-file
@vindex nnbabyl-active-file
-The name of the active file for the rmail box.
+The name of the active file for the rmail box. The default is
+@file{~/.rmail-active}
@item nnbabyl-get-new-mail
@vindex nnbabyl-get-new-mail
-If non-@code{nil}, @code{nnbabyl} will read incoming mail.
+If non-@code{nil}, @code{nnbabyl} will read incoming mail. Default is
+@code{t}
@end table
format. It should be used with some caution.
@vindex nnml-directory
-If you use this backend, Gnus will split all incoming mail into files,
+If you use this back end, Gnus will split all incoming mail into files,
one file for each mail, and put the articles into the corresponding
directories under the directory specified by the @code{nnml-directory}
variable. The default value is @file{~/Mail/}.
care of all that.
If you have a strict limit as to how many files you are allowed to store
-in your account, you should not use this backend. As each mail gets its
+in your account, you should not use this back end. As each mail gets its
own file, you might very well occupy thousands of inodes within a few
weeks. If this is no problem for you, and it isn't a problem for you
having your friendly systems administrator walking around, madly,
know that this is probably the fastest format to use. You do not have
to trudge through a big mbox file just to read your new mail.
-@code{nnml} is probably the slowest backend when it comes to article
+@code{nnml} is probably the slowest back end when it comes to article
splitting. It has to create lots of files, and it also generates
@sc{nov} databases for the incoming mails. This makes it the fastest
-backend when it comes to reading mail.
+back end when it comes to reading mail.
+
+@cindex self contained nnml servers
+When the marks file is used (which it is by default), @code{nnml}
+servers have the property that you may backup them using @code{tar} or
+similar, and later be able to restore them into Gnus (by adding the
+proper @code{nnml} server) and have all your marks be preserved. Marks
+for a group is usually stored in the @code{.marks} file (but see
+@code{nnml-marks-file-name}) within each @code{nnml} group's directory.
+Individual @code{nnml} groups are also possible to backup, use @kbd{G m}
+to restore the group (after restoring the backup into the nnml
+directory).
Virtual server settings:
@item nnml-directory
@vindex nnml-directory
All @code{nnml} directories will be placed under this directory.
+The default is the value of `message-directory' (whose default value is
+@file{~/Mail}).
@item nnml-active-file
@vindex nnml-active-file
-The active file for the @code{nnml} server.
+The active file for the @code{nnml} server. The default is
+@file{~/Mail/active"}.
@item nnml-newsgroups-file
@vindex nnml-newsgroups-file
The @code{nnml} group descriptions file. @xref{Newsgroups File
-Format}.
+Format}. The default is @file{~/Mail/newsgroups"}.
@item nnml-get-new-mail
@vindex nnml-get-new-mail
-If non-@code{nil}, @code{nnml} will read incoming mail.
+If non-@code{nil}, @code{nnml} will read incoming mail. The default is
+@code{t}.
@item nnml-nov-is-evil
@vindex nnml-nov-is-evil
-If non-@code{nil}, this backend will ignore any @sc{nov} files.
+If non-@code{nil}, this back end will ignore any @sc{nov} files. The
+default is @code{nil}.
@item nnml-nov-file-name
@vindex nnml-nov-file-name
@vindex nnml-prepare-save-mail-hook
Hook run narrowed to an article before saving.
+@item nnml-marks-is-evil
+@vindex nnml-marks-is-evil
+If non-@code{nil}, this back end will ignore any @sc{marks} files. The
+default is @code{nil}.
+
+@item nnml-marks-file-name
+@vindex nnml-marks-file-name
+The name of the @sc{marks} files. The default is @file{.marks}.
+
@end table
@findex nnml-generate-nov-databases
@cindex mh-e mail spool
@code{nnmh} is just like @code{nnml}, except that is doesn't generate
-@sc{nov} databases and it doesn't keep an active file. This makes
-@code{nnmh} a @emph{much} slower backend than @code{nnml}, but it also
-makes it easier to write procmail scripts for.
+@sc{nov} databases and it doesn't keep an active file or marks file.
+This makes @code{nnmh} a @emph{much} slower back end than @code{nnml},
+but it also makes it easier to write procmail scripts for.
Virtual server settings:
@table @code
@item nnmh-directory
@vindex nnmh-directory
-All @code{nnmh} directories will be located under this directory.
+All @code{nnmh} directories will be located under this directory. The
+default is the value of @code{message-directory} (whose default is
+@file{~/Mail})
@item nnmh-get-new-mail
@vindex nnmh-get-new-mail
-If non-@code{nil}, @code{nnmh} will read incoming mail.
+If non-@code{nil}, @code{nnmh} will read incoming mail. The default is
+@code{t}.
@item nnmh-be-safe
@vindex nnmh-be-safe
are. It will check date stamps and stat everything in sight, so
setting this to @code{t} will mean a serious slow-down. If you never
use anything but Gnus to read the @code{nnmh} articles, you do not have
-to set this variable to @code{t}.
+to set this variable to @code{t}. The default is @code{nil}.
@end table
@cindex mbox folders
@cindex mail folders
-@code{nnfolder} is a backend for storing each mail group in a separate
+@code{nnfolder} is a back end for storing each mail group in a separate
file. Each file is in the standard Un*x mbox format. @code{nnfolder}
will add extra headers to keep track of article numbers and arrival
dates.
+@cindex self contained nnfolder servers
+When the marks file is used (which it is by default), @code{nnfolder}
+servers have the property that you may backup them using @code{tar} or
+similar, and later be able to restore them into Gnus (by adding the
+proper @code{nnfolder} server) and have all your marks be preserved.
+Marks for a group is usually stored in a file named as the mbox file
+with @code{.mrk} concatenated to it (but see
+@code{nnfolder-marks-file-suffix}) within the @code{nnfolder} directory.
+Individual @code{nnfolder} groups are also possible to backup, use
+@kbd{G m} to restore the group (after restoring the backup into the
+@code{nnfolder} directory).
+
Virtual server settings:
@table @code
@item nnfolder-directory
@vindex nnfolder-directory
All the @code{nnfolder} mail boxes will be stored under this directory.
+The default is the value of @code{message-directory} (whose default is
+@file{~/Mail})
@item nnfolder-active-file
@vindex nnfolder-active-file
-The name of the active file.
+The name of the active file. The default is @file{~/Mail/active}.
@item nnfolder-newsgroups-file
@vindex nnfolder-newsgroups-file
-The name of the group descriptions file. @xref{Newsgroups File Format}.
+The name of the group descriptions file. @xref{Newsgroups File
+Format}. The default is @file{~/Mail/newsgroups"}
@item nnfolder-get-new-mail
@vindex nnfolder-get-new-mail
-If non-@code{nil}, @code{nnfolder} will read incoming mail.
+If non-@code{nil}, @code{nnfolder} will read incoming mail. The default
+is @code{t}
@item nnfolder-save-buffer-hook
@vindex nnfolder-save-buffer-hook
@item nnfolder-nov-is-evil
@vindex nnfolder-nov-is-evil
-If non-@code{nil}, this backend will ignore any @sc{nov} files.
+If non-@code{nil}, this back end will ignore any @sc{nov} files. The
+default is @code{nil}.
+
+@item nnfolder-nov-file-suffix
+@vindex nnfolder-nov-file-suffix
+The extension for @sc{nov} files. The default is @file{.nov}.
+
+@item nnfolder-nov-directory
+@vindex nnfolder-nov-directory
+The directory where the @sc{nov} files should be stored. If nil,
+@code{nnfolder-directory} is used.
+
+@item nnfolder-marks-is-evil
+@vindex nnfolder-marks-is-evil
+If non-@code{nil}, this back end will ignore any @sc{marks} files. The
+default is @code{nil}.
+
+@item nnfolder-marks-file-suffix
+@vindex nnfolder-marks-file-suffix
+The extension for @sc{marks} files. The default is @file{.mrk}.
+
+@item nnfolder-marks-directory
+@vindex nnfolder-marks-directory
+The directory where the @sc{marks} files should be stored. If nil,
+@code{nnfolder-directory} is used.
@end table
@code{nnfolder-directory}. This only works if you use long file names,
though.
-@node Comparing Mail Backends
-@subsubsection Comparing Mail Backends
+@node Comparing Mail Back Ends
+@subsubsection Comparing Mail Back Ends
-First, just for terminology, the @dfn{backend} is the common word for a
+First, just for terminology, the @dfn{back end} is the common word for a
low-level access method---a transport, if you will, by which something
is acquired. The sense is that one's mail has to come from somewhere,
-and so selection of a suitable backend is required in order to get that
+and so selection of a suitable back end is required in order to get that
mail within spitting distance of Gnus.
The same concept exists for Usenet itself: Though access to articles is
articles lay (the machine which today we call an @sc{nntp} server), and
access was by the reader stepping into the articles' directory spool
area directly. One can still select between either the @code{nntp} or
-@code{nnspool} backends, to select between these methods, if one happens
+@code{nnspool} back ends, to select between these methods, if one happens
actually to live on the server (or can see its spool directly, anyway,
via NFS).
-The goal in selecting a mail backend is to pick one which
+The goal in selecting a mail back end is to pick one which
simultaneously represents a suitable way of dealing with the original
format plus leaving mail in a form that is convenient to use in the
future. Here are some high and low points on each:
@samp{From:} header.) Because Emacs and therefore Gnus emanate
historically from the Unix environment, it is simplest if one does not
mess a great deal with the original mailbox format, so if one chooses
-this backend, Gnus' primary activity in getting mail from the real spool
+this back end, Gnus' primary activity in getting mail from the real spool
area to Gnus' preferred directory is simply to copy it, with no
(appreciable) format change in the process. It is the ``dumbest'' way
to move mail into availability in the Gnus environment. This makes it
@item nnml
-@code{nnml} is the backend which smells the most as though you were
+@code{nnml} is the back end which smells the most as though you were
actually operating with an @code{nnspool}-accessed Usenet system. (In
fact, I believe @code{nnml} actually derived from @code{nnspool} code,
lo these years ago.) One's mail is taken from the original spool file,
the filesystem is your own and space is not at a premium, @code{nnml}
wins big.
-It is also problematic using this backend if you are living in a
+It is also problematic using this back end if you are living in a
FAT16-based Windows world, since much space will be wasted on all these
tiny files.
little bit of optimization to this so that each of one's mail groups has
a Unix mail box file. It's faster than @code{nnmbox} because each group
can be parsed separately, and still provides the simple Unix mail box
-format requiring minimal effort in moving the mail around. In addition,
-it maintains an ``active'' file making it much faster for Gnus to figure
+format requiring minimal effort in moving the mail around. In addition,
+it maintains an ``active'' file making it much faster for Gnus to figure
out how many messages there are in each separate group.
If you have groups that are expected to have a massive amount of
messages, @code{nnfolder} is not the best choice, but if you receive
only a moderate amount of mail, @code{nnfolder} is probably the most
-friendly mail backend all over.
+friendly mail back end all over.
@end table
go through a cumbersome subscription procedure, and most people don't
even know what a news group is.
-The problem with this scenario is that web browsers are not very good at
-being newsreaders. They do not keep track of what articles you've read;
-they do not allow you to score on subjects you're interested in; they do
+The problem with this scenario is that web browsers are not very good at
+being newsreaders. They do not keep track of what articles you've read;
+they do not allow you to score on subjects you're interested in; they do
not allow off-line browsing; they require you to click around and drive
you mad in the end.
-So---if web browsers suck at reading discussion forums, why not use Gnus
+So---if web browsers suck at reading discussion forums, why not use Gnus
to do it instead?
-Gnus has been getting a bit of a collection of backends for providing
+Gnus has been getting a bit of a collection of back ends for providing
interfaces to these sources.
@menu
-* Web Searches:: Creating groups from articles that match a string.
-* Slashdot:: Reading the Slashdot comments.
-* Ultimate:: The Ultimate Bulletin Board systems.
-* Web Archive:: Reading mailing list archived on web.
-* RSS:: Reading RDF site summary.
-* Customizing w3:: Doing stuff to Emacs/w3 from Gnus.
+* Web Searches:: Creating groups from articles that match a string.
+* Slashdot:: Reading the Slashdot comments.
+* Ultimate:: The Ultimate Bulletin Board systems.
+* Web Archive:: Reading mailing list archived on web.
+* RSS:: Reading RDF site summary.
+* Customizing w3:: Doing stuff to Emacs/w3 from Gnus.
@end menu
All the web sources require Emacs/w3 and the url library to work.
The main caveat with all these web sources is that they probably won't
-work for a very long time. Gleaning information from the @sc{html} data
-is guesswork at best, and when the layout is altered, the Gnus backend
-will fail. If you have reasonably new versions of these backends,
+work for a very long time. Gleaning information from the @sc{html} data
+is guesswork at best, and when the layout is altered, the Gnus back end
+will fail. If you have reasonably new versions of these back ends,
though, you should be ok.
One thing all these Web methods have in common is that the Web sources
Unplugged}) handle downloading articles, and then you can read them at
leisure from your local disk. No more World Wide Wait for you.
+@node Archiving Mail
+@subsection Archiving Mail
+@cindex archiving mail
+@cindex backup of mail
+
+Some of the back ends, notably nnml and nnfolder, now actually store
+the article marks with each group. For these servers, archiving and
+restoring a group while preserving marks is fairly simple.
+
+(Preserving the group level and group parameters as well still
+requires ritual dancing and sacrifices to the @code{.newsrc.eld} deity
+though.)
+
+To archive an entire @code{nnml} or @code{nnfolder} server, take a
+recursive copy of the server directory. There is no need to shut down
+Gnus, so archiving may be invoked by @code{cron} or similar. You
+restore the data by restoring the directory tree, and adding a server
+definition pointing to that directory in Gnus. The @ref{Article
+Backlog}, @ref{Asynchronous Fetching} and other things might interfer
+with overwriting data, so you may want to shut down Gnus before you
+restore the data.
+
+It is also possible to archive individual @code{nnml} or
+@code{nnfolder} groups, while preserving marks. For @code{nnml}, you
+copy all files in the group's directory. For @code{nnfolder} you need
+to copy both the base folder file itself (@code{FOO}, say), and the
+marks file (@code{FOO.mrk} in this example). Restoring the group is
+done with @kbd{G m} from the Group buffer. The last step makes Gnus
+notice the new directory.
@node Web Searches
@subsection Web Searches
the commercials, so, like, with Gnus you can do @emph{rad}, rilly,
searches without having to use a browser.
-The @code{nnweb} backend allows an easy interface to the mighty search
+The @code{nnweb} back end allows an easy interface to the mighty search
engine. You create an @code{nnweb} group, enter a search pattern, and
then enter the group and read the articles like you would any normal
group. The @kbd{G w} command in the group buffer (@pxref{Foreign
'((nnslashdot "")))
@end lisp
-This will make Gnus query the @code{nnslashdot} backend for new comments
+This will make Gnus query the @code{nnslashdot} back end for new comments
and groups. The @kbd{F} command will subscribe each new news article as
a new Gnus group, and you can read the comments by entering these
groups. (Note that the default subscription method is to subscribe new
@item nnslashdot-directory
@vindex nnslashdot-directory
-Where @code{nnslashdot} will store its files. The default value is
+Where @code{nnslashdot} will store its files. The default is
@samp{~/News/slashdot/}.
@item nnslashdot-active-url
@vindex nnslashdot-active-url
-The @sc{url} format string that will be used to fetch the information on
+The @sc{url} format string that will be used to fetch the information on
news articles and comments. The default is
@samp{http://slashdot.org/search.pl?section=&min=%d}.
information Gnus needs to keep groups updated.
The easiest way to get started with @code{nnultimate} is to say
-something like the following in the group buffer: @kbd{B nnultimate RET
+something like the following in the group buffer: @kbd{B nnultimate RET
http://www.tcj.com/messboard/ubbcgi/ RET}. (Substitute the @sc{url}
(not including @samp{Ultimate.cgi} or the like at the end) for a forum
you're interested in; there's quite a list of them on the Ultimate web
www.egroups.com RET your@@email.address RET}. (Substitute the
@sc{an_egroup} with the mailing list you subscribed, the
@sc{your@@email.address} with your email address.), or to browse the
-backend by @kbd{B nnwarchive RET mail-archive RET}.
+back end by @kbd{B nnwarchive RET mail-archive RET}.
The following @code{nnwarchive} variables can be altered:
@end table
+The following code may be helpful, if you want to show the description in
+the summary buffer.
+
+@lisp
+(add-to-list 'nnmail-extra-headers nnrss-description-field)
+(setq gnus-summary-line-format "%U%R%z%I%(%[%4L: %-15,15f%]%) %s%uX\n")
+
+(defun gnus-user-format-function-X (header)
+ (let ((descr
+ (assq nnrss-description-field (mail-header-extra header))))
+ (if descr (concat "\n\t" (cdr descr)) "")))
+@end lisp
+
+The following code may be useful to open an nnrss url directly from the
+summary buffer.
+@lisp
+(require 'browse-url)
+
+(defun browse-nnrss-url( arg )
+ (interactive "p")
+ (let ((url (assq nnrss-url-field
+ (mail-header-extra
+ (gnus-data-header
+ (assq (gnus-summary-article-number)
+ gnus-newsgroup-data))))))
+ (if url
+ (browse-url (cdr url))
+ (gnus-summary-scroll-up arg))))
+
+(eval-after-load "gnus"
+ #'(define-key gnus-summary-mode-map
+ (kbd "<RET>") 'browse-nnrss-url))
+(add-to-list 'nnmail-extra-headers nnrss-url-field)
+@end lisp
+
@node Customizing w3
@subsection Customizing w3
@cindex w3
@cindex url
@cindex Netscape
-Gnus uses the url library to fetch web pages and Emacs/w3 to display web
+Gnus uses the url library to fetch web pages and Emacs/w3 to display web
pages. Emacs/w3 is documented in its own manual, but there are some
things that may be more relevant for Gnus users.
For instance, a common question is how to make Emacs/w3 follow links
-using the @code{browse-url} functions (which will call some external web
+using the @code{browse-url} functions (which will call some external web
browser like Netscape). Here's one way:
@lisp
@sc{html} in the Gnus article buffers will use @code{browse-url} to
follow the link.
+@node IMAP
+@section @sc{imap}
+@cindex nnimap
+@cindex @sc{imap}
-@node Other Sources
-@section Other Sources
-
-Gnus can do more than just read news or mail. The methods described
-below allow Gnus to view directories and files as if they were
-newsgroups.
+@sc{imap} is a network protocol for reading mail (or news, or ...),
+think of it as a modernized @sc{nntp}. Connecting to a @sc{imap}
+server is much similar to connecting to a news server, you just
+specify the network address of the server.
-@menu
-* Directory Groups:: You can read a directory as if it was a newsgroup.
-* Anything Groups:: Dired? Who needs dired?
-* Document Groups:: Single files can be the basis of a group.
-* SOUP:: Reading @sc{soup} packets ``offline''.
-* Mail-To-News Gateways:: Posting articles via mail-to-news gateways.
-* IMAP:: Using Gnus as a @sc{imap} client.
-@end menu
+@sc{imap} has two properties. First, @sc{imap} can do everything that
+POP can, it can hence be viewed as POP++. Secondly, @sc{imap} is a
+mail storage protocol, similar to @sc{nntp} being a news storage
+protocol. (@sc{imap} offers more features than @sc{nntp} because news
+is more or less read-only whereas mail is read-write.)
+If you want to use @sc{imap} as POP++, use an imap entry in
+mail-sources. With this, Gnus will fetch mails from the @sc{imap}
+server and store them on the local disk. This is not the usage
+described in this section. @xref{Mail Sources}.
-@node Directory Groups
-@subsection Directory Groups
-@cindex nndir
-@cindex directory groups
+If you want to use @sc{imap} as a mail storage protocol, use an nnimap
+entry in gnus-secondary-select-methods. With this, Gnus will
+manipulate mails stored on the @sc{imap} server. This is the kind of
+usage explained in this section.
-If you have a directory that has lots of articles in separate files in
-it, you might treat it as a newsgroup. The files have to have numerical
-names, of course.
+A server configuration in @code{~/.gnus} with a few @sc{imap} servers
+might look something like this:
-This might be an opportune moment to mention @code{ange-ftp} (and its
-successor @code{efs}), that most wonderful of all wonderful Emacs
-packages. When I wrote @code{nndir}, I didn't think much about it---a
-backend to read directories. Big deal.
+@lisp
+(setq gnus-secondary-select-methods
+ '((nnimap "simpleserver") ; no special configuration
+ ; perhaps a ssh port forwarded server:
+ (nnimap "dolk"
+ (nnimap-address "localhost")
+ (nnimap-server-port 1430))
+ ; a UW server running on localhost
+ (nnimap "barbar"
+ (nnimap-server-port 143)
+ (nnimap-address "localhost")
+ (nnimap-list-pattern ("INBOX" "mail/*")))
+ ; anonymous public cyrus server:
+ (nnimap "cyrus.andrew.cmu.edu"
+ (nnimap-authenticator anonymous)
+ (nnimap-list-pattern "archive.*")
+ (nnimap-stream network))
+ ; a ssl server on a non-standard port:
+ (nnimap "vic20"
+ (nnimap-address "vic20.somewhere.com")
+ (nnimap-server-port 9930)
+ (nnimap-stream ssl))))
+@end lisp
-@code{ange-ftp} changes that picture dramatically. For instance, if you
-enter the @code{ange-ftp} file name
-@file{/ftp.hpc.uh.edu:/pub/emacs/ding-list/} as the directory name,
-@code{ange-ftp} or @code{efs} will actually allow you to read this
-directory over at @samp{sina} as a newsgroup. Distributed news ahoy!
+(Note that for SSL/TLS to work, you need the external library
+@samp{ssl.el}, see below.)
-@code{nndir} will use @sc{nov} files if they are present.
+The following variables can be used to create a virtual @code{nnimap}
+server:
-@code{nndir} is a ``read-only'' backend---you can't delete or expire
-articles with this method. You can use @code{nnmh} or @code{nnml} for
-whatever you use @code{nndir} for, so you could switch to any of those
-methods if you feel the need to have a non-read-only @code{nndir}.
+@table @code
+@item nnimap-address
+@vindex nnimap-address
-@node Anything Groups
-@subsection Anything Groups
-@cindex nneething
+The address of the remote @sc{imap} server. Defaults to the virtual
+server name if not specified.
-From the @code{nndir} backend (which reads a single spool-like
-directory), it's just a hop and a skip to @code{nneething}, which
-pretends that any arbitrary directory is a newsgroup. Strange, but
-true.
+@item nnimap-server-port
+@vindex nnimap-server-port
+Port on server to contact. Defaults to port 143, or 993 for SSL.
-When @code{nneething} is presented with a directory, it will scan this
-directory and assign article numbers to each file. When you enter such
-a group, @code{nneething} must create ``headers'' that Gnus can use.
-After all, Gnus is a newsreader, in case you're forgetting.
-@code{nneething} does this in a two-step process. First, it snoops each
-file in question. If the file looks like an article (i.e., the first
-few lines look like headers), it will use this as the head. If this is
-just some arbitrary file without a head (e.g. a C source file),
-@code{nneething} will cobble up a header out of thin air. It will use
-file ownership, name and date and do whatever it can with these
-elements.
+Note that this should be an integer, example server specification:
-All this should happen automatically for you, and you will be presented
-with something that looks very much like a newsgroup. Totally like a
-newsgroup, to be precise. If you select an article, it will be displayed
-in the article buffer, just as usual.
+@lisp
+(nnimap "mail.server.com"
+ (nnimap-server-port 4711))
+@end lisp
-If you select a line that represents a directory, Gnus will pop you into
-a new summary buffer for this @code{nneething} group. And so on. You can
-traverse the entire disk this way, if you feel like, but remember that
-Gnus is not dired, really, and does not intend to be, either.
+@item nnimap-list-pattern
+@vindex nnimap-list-pattern
+String or list of strings of mailboxes to limit available groups to.
+This is used when the server has very many mailboxes and you're only
+interested in a few -- some servers export your home directory via
+@sc{imap}, you'll probably want to limit the mailboxes to those in
+@file{~/Mail/*} then.
-There are two overall modes to this action---ephemeral or solid. When
-doing the ephemeral thing (i.e., @kbd{G D} from the group buffer), Gnus
-will not store information on what files you have read, and what files
-are new, and so on. If you create a solid @code{nneething} group the
-normal way with @kbd{G m}, Gnus will store a mapping table between
-article numbers and file names, and you can treat this group like any
-other groups. When you activate a solid @code{nneething} group, you will
-be told how many unread articles it contains, etc., etc.
+The string can also be a cons of REFERENCE and the string as above, what
+REFERENCE is used for is server specific, but on the University of
+Washington server it's a directory that will be concatenated with the
+mailbox.
-Some variables:
+Example server specification:
-@table @code
-@item nneething-map-file-directory
-@vindex nneething-map-file-directory
-All the mapping files for solid @code{nneething} groups will be stored
-in this directory, which defaults to @file{~/.nneething/}.
+@lisp
+(nnimap "mail.server.com"
+ (nnimap-list-pattern ("INBOX" "Mail/*" "alt.sex.*"
+ ("~friend/Mail/" . "list/*"))))
+@end lisp
-@item nneething-exclude-files
-@vindex nneething-exclude-files
-All files that match this regexp will be ignored. Nice to use to exclude
-auto-save files and the like, which is what it does by default.
+@item nnimap-stream
+@vindex nnimap-stream
+The type of stream used to connect to your server. By default, nnimap
+will detect and automatically use all of the below, with the exception
+of SSL/TLS. (IMAP over SSL/TLS is being replaced by STARTTLS, which
+can be automatically detected, but it's not widely deployed yet.)
-@item nneething-include-files
-@vindex nneething-include-files
-Regexp saying what files to include in the group. If this variable is
-non-@code{nil}, only files matching this regexp will be included.
+Example server specification:
-@item nneething-map-file
-@vindex nneething-map-file
-Name of the map files.
-@end table
+@lisp
+(nnimap "mail.server.com"
+ (nnimap-stream ssl))
+@end lisp
+Please note that the value of @code{nnimap-stream} is a symbol!
-@node Document Groups
-@subsection Document Groups
-@cindex nndoc
-@cindex documentation group
-@cindex help group
+@itemize @bullet
+@item
+@dfn{gssapi:} Connect with GSSAPI (usually kerberos 5). Requires the
+@samp{imtest} program.
+@item
+@dfn{kerberos4:} Connect with kerberos 4. Requires the @samp{imtest} program.
+@item
+@dfn{starttls:} Connect via the STARTTLS extension (similar to
+SSL). Requires the external library @samp{starttls.el} and program
+@samp{starttls}.
+@item
+@dfn{ssl:} Connect through SSL. Requires OpenSSL (the program
+@samp{openssl}) or SSLeay (@samp{s_client}) as well as the external
+library @samp{ssl.el}.
+@item
+@dfn{shell:} Use a shell command to start @sc{imap} connection.
+@item
+@dfn{network:} Plain, TCP/IP network connection.
+@end itemize
-@code{nndoc} is a cute little thing that will let you read a single file
-as a newsgroup. Several files types are supported:
+@vindex imap-kerberos4-program
+The @samp{imtest} program is shipped with Cyrus IMAPD. If you're
+using @samp{imtest} from Cyrus IMAPD < 2.0.14 (which includes version
+1.5.x and 1.6.x) you need to frob @code{imap-process-connection-type}
+to make @code{imap.el} use a pty instead of a pipe when communicating
+with @samp{imtest}. You will then suffer from a line length
+restrictions on IMAP commands, which might make Gnus seem to hang
+indefinitely if you have many articles in a mailbox. The variable
+@code{imap-kerberos4-program} contain parameters to pass to the imtest
+program.
-@table @code
-@cindex babyl
-@cindex rmail mbox
+@vindex imap-ssl-program
+For SSL connections, the OpenSSL program is available from
+@uref{http://www.openssl.org/}. OpenSSL was formerly known as SSLeay,
+and nnimap support it too - altough the most recent versions of
+SSLeay, 0.9.x, are known to have serious bugs making it
+useless. Earlier versions, especially 0.8.x, of SSLeay are known to
+work. The variable @code{imap-ssl-program} contain parameters to pass
+to OpenSSL/SSLeay. You also need @samp{ssl.el} (from the W3
+distribution, for instance).
-@item babyl
-The babyl (rmail) mail box.
-@cindex mbox
-@cindex Unix mbox
+@vindex imap-shell-program
+@vindex imap-shell-host
+For @sc{imap} connections using the @code{shell} stream, the variable
+@code{imap-shell-program} specify what program to call.
-@item mbox
-The standard Unix mbox file.
+@item nnimap-authenticator
+@vindex nnimap-authenticator
-@cindex MMDF mail box
-@item mmdf
-The MMDF mail box format.
+The authenticator used to connect to the server. By default, nnimap
+will use the most secure authenticator your server is capable of.
-@item news
-Several news articles appended into a file.
+Example server specification:
-@item rnews
-@cindex rnews batch files
-The rnews batch transport format.
-@cindex forwarded messages
+@lisp
+(nnimap "mail.server.com"
+ (nnimap-authenticator anonymous))
+@end lisp
-@item forward
-Forwarded articles.
+Please note that the value of @code{nnimap-authenticator} is a symbol!
-@item nsmail
-Netscape mail boxes.
+@itemize @bullet
+@item
+@dfn{gssapi:} GSSAPI (usually kerberos 5) authentication. Require
+external program @code{imtest}.
+@item
+@dfn{kerberos4:} Kerberos authentication. Require external program
+@code{imtest}.
+@item
+@dfn{digest-md5:} Encrypted username/password via DIGEST-MD5. Require
+external library @code{digest-md5.el}.
+@item
+@dfn{cram-md5:} Encrypted username/password via CRAM-MD5.
+@item
+@dfn{login:} Plain-text username/password via LOGIN.
+@item
+@dfn{anonymous:} Login as `anonymous', supplying your emailadress as password.
+@end itemize
-@item mime-parts
-MIME multipart messages.
+@item nnimap-expunge-on-close
+@cindex Expunging
+@vindex nnimap-expunge-on-close
+Unlike Parmenides the @sc{imap} designers has decided that things that
+doesn't exist actually does exist. More specifically, @sc{imap} has
+this concept of marking articles @code{Deleted} which doesn't actually
+delete them, and this (marking them @code{Deleted}, that is) is what
+nnimap does when you delete a article in Gnus (with @kbd{G DEL} or
+similar).
-@item standard-digest
-The standard (RFC 1153) digest format.
+Since the articles aren't really removed when we mark them with the
+@code{Deleted} flag we'll need a way to actually delete them. Feel like
+running in circles yet?
+
+Traditionally, nnimap has removed all articles marked as @code{Deleted}
+when closing a mailbox but this is now configurable by this server
+variable.
+
+The possible options are:
+
+@table @code
+
+@item always
+The default behavior, delete all articles marked as "Deleted" when
+closing a mailbox.
+@item never
+Never actually delete articles. Currently there is no way of showing
+the articles marked for deletion in nnimap, but other @sc{imap} clients
+may allow you to do this. If you ever want to run the EXPUNGE command
+manually, @xref{Expunging mailboxes}.
+@item ask
+When closing mailboxes, nnimap will ask if you wish to expunge deleted
+articles or not.
-@item slack-digest
-Non-standard digest format---matches most things, but does it badly.
@end table
-You can also use the special ``file type'' @code{guess}, which means
-that @code{nndoc} will try to guess what file type it is looking at.
-@code{digest} means that @code{nndoc} should guess what digest type the
-file is.
+@item nnimap-importantize-dormant
+@vindex nnimap-importantize-dormant
-@code{nndoc} will not try to change the file or insert any extra headers into
-it---it will simply, like, let you use the file as the basis for a
-group. And that's it.
+If non-nil, marks dormant articles as ticked (as well), for other IMAP
+clients. Within Gnus, dormant articles will naturally still (only) be
+marked as ticked. This is to make dormant articles stand out, just
+like ticked articles, in other IMAP clients. (In other words, Gnus has
+two ``Tick'' marks and IMAP has only one.)
-If you have some old archived articles that you want to insert into your
-new & spiffy Gnus mail backend, @code{nndoc} can probably help you with
-that. Say you have an old @file{RMAIL} file with mail that you now want
-to split into your new @code{nnml} groups. You look at that file using
-@code{nndoc} (using the @kbd{G f} command in the group buffer
-(@pxref{Foreign Groups})), set the process mark on all the articles in
-the buffer (@kbd{M P b}, for instance), and then re-spool (@kbd{B r})
-using @code{nnml}. If all goes well, all the mail in the @file{RMAIL}
-file is now also stored in lots of @code{nnml} directories, and you can
-delete that pesky @file{RMAIL} file. If you have the guts!
+Probably the only reason for frobing this would be if you're trying
+enable per-user persistant dormant flags, using something like:
-Virtual server variables:
+@lisp
+(setcdr (assq 'dormant nnimap-mark-to-flag-alist)
+ (format "gnus-dormant-%s" (user-login-name)))
+(setcdr (assq 'dormant nnimap-mark-to-predicate-alist)
+ (format "KEYWORD gnus-dormant-%s" (user-login-name)))
+@end lisp
-@table @code
-@item nndoc-article-type
-@vindex nndoc-article-type
-This should be one of @code{mbox}, @code{babyl}, @code{digest},
-@code{news}, @code{rnews}, @code{mmdf}, @code{forward}, @code{rfc934},
-@code{rfc822-forward}, @code{mime-parts}, @code{standard-digest},
-@code{slack-digest}, @code{clari-briefs}, @code{nsmail} or @code{guess}.
+In this case, you would not want the per-user dormant flag showing up
+as ticked for other users.
+
+@item nnimap-expunge-search-string
+@cindex Expunging
+@vindex nnimap-expunge-search-string
+
+This variable contain the IMAP search command sent to server when
+searching for articles eligible for expiring. The default is
+@code{"UID %s NOT SINCE %s"}, where the first @code{%s} is replaced by
+UID set and the second @code{%s} is replaced by a date.
+
+Probably the only useful value to change this to is
+@code{"UID %s NOT SENTSINCE %s"}, which makes nnimap use the Date: in
+messages instead of the internal article date. See section 6.4.4 of
+RFC 2060 for more information on valid strings.
+
+@item nnimap-authinfo-file
+@vindex nnimap-authinfo-file
+
+A file containing credentials used to log in on servers. The format is
+(almost) the same as the @code{ftp} @file{~/.netrc} file. See the
+variable @code{nntp-authinfo-file} for exact syntax; also see
+@ref{NNTP}.
-@item nndoc-post-type
-@vindex nndoc-post-type
-This variable says whether Gnus is to consider the group a news group or
-a mail group. There are two valid values: @code{mail} (the default)
-and @code{news}.
@end table
@menu
-* Document Server Internals:: How to add your own document types.
+* Splitting in IMAP:: Splitting mail with nnimap.
+* Editing IMAP ACLs:: Limiting/enabling other users access to a mailbox.
+* Expunging mailboxes:: Equivalent of a "compress mailbox" button.
@end menu
-@node Document Server Internals
-@subsubsection Document Server Internals
-Adding new document types to be recognized by @code{nndoc} isn't
-difficult. You just have to whip up a definition of what the document
-looks like, write a predicate function to recognize that document type,
-and then hook into @code{nndoc}.
+@node Splitting in IMAP
+@subsection Splitting in @sc{imap}
+@cindex splitting imap mail
-First, here's an example document type definition:
+Splitting is something Gnus users has loved and used for years, and now
+the rest of the world is catching up. Yeah, dream on, not many
+@sc{imap} server has server side splitting and those that have splitting
+seem to use some non-standard protocol. This means that @sc{imap}
+support for Gnus has to do it's own splitting.
-@example
-(mmdf
- (article-begin . "^\^A\^A\^A\^A\n")
- (body-end . "^\^A\^A\^A\^A\n"))
-@end example
+And it does.
-The definition is simply a unique @dfn{name} followed by a series of
-regexp pseudo-variable settings. Below are the possible
-variables---don't be daunted by the number of variables; most document
-types can be defined with very few settings:
+Here are the variables of interest:
@table @code
-@item first-article
-If present, @code{nndoc} will skip past all text until it finds
-something that match this regexp. All text before this will be
-totally ignored.
-@item article-begin
-This setting has to be present in all document type definitions. It
-says what the beginning of each article looks like.
+@item nnimap-split-crosspost
+@cindex splitting, crosspost
+@cindex crosspost
+@vindex nnimap-split-crosspost
-@item head-begin-function
-If present, this should be a function that moves point to the head of
-the article.
+If non-nil, do crossposting if several split methods match the mail. If
+nil, the first match in @code{nnimap-split-rule} found will be used.
-@item nndoc-head-begin
-If present, this should be a regexp that matches the head of the
-article.
+Nnmail equivalent: @code{nnmail-crosspost}.
-@item nndoc-head-end
-This should match the end of the head of the article. It defaults to
-@samp{^$}---the empty line.
+@item nnimap-split-inbox
+@cindex splitting, inbox
+@cindex inbox
+@vindex nnimap-split-inbox
-@item body-begin-function
-If present, this function should move point to the beginning of the body
-of the article.
+A string or a list of strings that gives the name(s) of @sc{imap}
+mailboxes to split from. Defaults to nil, which means that splitting is
+disabled!
-@item body-begin
-This should match the beginning of the body of the article. It defaults
-to @samp{^\n}.
+@lisp
+(setq nnimap-split-inbox
+ '("INBOX" ("~/friend/Mail" . "lists/*") "lists.imap"))
+@end lisp
-@item body-end-function
-If present, this function should move point to the end of the body of
-the article.
+No nnmail equivalent.
-@item body-end
-If present, this should match the end of the body of the article.
+@item nnimap-split-rule
+@cindex Splitting, rules
+@vindex nnimap-split-rule
-@item file-end
-If present, this should match the end of the file. All text after this
-regexp will be totally ignored.
+New mail found in @code{nnimap-split-inbox} will be split according to
+this variable.
-@end table
+This variable contains a list of lists, where the first element in the
+sublist gives the name of the @sc{imap} mailbox to move articles
+matching the regexp in the second element in the sublist. Got that?
+Neither did I, we need examples.
-So, using these variables @code{nndoc} is able to dissect a document
-file into a series of articles, each with a head and a body. However, a
-few more variables are needed since not all document types are all that
-news-like---variables needed to transform the head or the body into
-something that's palatable for Gnus:
+@lisp
+(setq nnimap-split-rule
+ '(("INBOX.nnimap"
+ "^Sender: owner-nnimap@@vic20.globalcom.se")
+ ("INBOX.junk" "^Subject:.*MAKE MONEY")
+ ("INBOX.private" "")))
+@end lisp
-@table @code
-@item prepare-body-function
-If present, this function will be called when requesting an article. It
-will be called with point at the start of the body, and is useful if the
-document has encoded some parts of its contents.
+This will put all articles from the nnimap mailing list into mailbox
+INBOX.nnimap, all articles containing MAKE MONEY in the Subject: line
+into INBOX.junk and everything else in INBOX.private.
-@item article-transform-function
-If present, this function is called when requesting an article. It's
-meant to be used for more wide-ranging transformation of both head and
-body of the article.
+The first string may contain `\\1' forms, like the ones used by
+replace-match to insert sub-expressions from the matched text. For
+instance:
-@item generate-head-function
-If present, this function is called to generate a head that Gnus can
-understand. It is called with the article number as a parameter, and is
-expected to generate a nice head for the article in question. It is
-called when requesting the headers of all articles.
+@lisp
+("INBOX.lists.\\1" "^Sender: owner-\\([a-z-]+\\)@@")
+@end lisp
-@end table
+The second element can also be a function. In that case, it will be
+called with the first element of the rule as the argument, in a buffer
+containing the headers of the article. It should return a non-nil value
+if it thinks that the mail belongs in that group.
-Let's look at the most complicated example I can come up with---standard
-digests:
+Nnmail users might recollect that the last regexp had to be empty to
+match all articles (like in the example above). This is not required in
+nnimap. Articles not matching any of the regexps will not be moved out
+of your inbox. (This might affect performance if you keep lots of
+unread articles in your inbox, since the splitting code would go over
+them every time you fetch new mail.)
-@example
-(standard-digest
- (first-article . ,(concat "^" (make-string 70 ?-) "\n\n+"))
- (article-begin . ,(concat "\n\n" (make-string 30 ?-) "\n\n+"))
- (prepare-body-function . nndoc-unquote-dashes)
- (body-end-function . nndoc-digest-body-end)
- (head-end . "^ ?$")
- (body-begin . "^ ?\n")
- (file-end . "^End of .*digest.*[0-9].*\n\\*\\*\\|^End of.*Digest *$")
- (subtype digest guess))
-@end example
+These rules are processed from the beginning of the alist toward the
+end. The first rule to make a match will "win", unless you have
+crossposting enabled. In that case, all matching rules will "win".
-We see that all text before a 70-width line of dashes is ignored; all
-text after a line that starts with that @samp{^End of} is also ignored;
-each article begins with a 30-width line of dashes; the line separating
-the head from the body may contain a single space; and that the body is
-run through @code{nndoc-unquote-dashes} before being delivered.
+This variable can also have a function as its value, the function will
+be called with the headers narrowed and should return a group where it
+thinks the article should be split to. See @code{nnimap-split-fancy}.
-To hook your own document definition into @code{nndoc}, use the
-@code{nndoc-add-type} function. It takes two parameters---the first is
-the definition itself and the second (optional) parameter says where in
-the document type definition alist to put this definition. The alist is
-traversed sequentially, and @code{nndoc-TYPE-type-p} is called for a given type @code{TYPE}. So @code{nndoc-mmdf-type-p} is called to see whether a document
-is of @code{mmdf} type, and so on. These type predicates should return
-@code{nil} if the document is not of the correct type; @code{t} if it is
-of the correct type; and a number if the document might be of the
-correct type. A high number means high probability; a low number means
-low probability with @samp{0} being the lowest valid number.
+The splitting code tries to create mailboxes if it needs to.
+To allow for different split rules on different virtual servers, and
+even different split rules in different inboxes on the same server,
+the syntax of this variable have been extended along the lines of:
-@node SOUP
-@subsection SOUP
-@cindex SOUP
-@cindex offline
+@lisp
+(setq nnimap-split-rule
+ '(("my1server" (".*" (("ding" "ding@@gnus.org")
+ ("junk" "From:.*Simon")))
+ ("my2server" ("INBOX" nnimap-split-fancy))
+ ("my[34]server" (".*" (("private" "To:.*Simon")
+ ("junk" my-junk-func)))))
+@end lisp
-In the PC world people often talk about ``offline'' newsreaders. These
-are thingies that are combined reader/news transport monstrosities.
-With built-in modem programs. Yecchh!
+The virtual server name is in fact a regexp, so that the same rules
+may apply to several servers. In the example, the servers
+@code{my3server} and @code{my4server} both use the same rules.
+Similarly, the inbox string is also a regexp. The actual splitting
+rules are as before, either a function, or a list with group/regexp or
+group/function elements.
-Of course, us Unix Weenie types of human beans use things like
-@code{uucp} and, like, @code{nntpd} and set up proper news and mail
-transport things like Ghod intended. And then we just use normal
-newsreaders.
+Nnmail equivalent: @code{nnmail-split-methods}.
-However, it can sometimes be convenient to do something that's a bit
-easier on the brain if you have a very slow modem, and you're not really
-that interested in doing things properly.
+@item nnimap-split-predicate
+@cindex splitting
+@vindex nnimap-split-predicate
-A file format called @sc{soup} has been developed for transporting news
-and mail from servers to home machines and back again. It can be a bit
-fiddly.
+Mail matching this predicate in @code{nnimap-split-inbox} will be
+split, it is a string and the default is @samp{UNSEEN UNDELETED}.
-First some terminology:
+This might be useful if you use another @sc{imap} client to read mail in
+your inbox but would like Gnus to split all articles in the inbox
+regardless of readedness. Then you might change this to
+@samp{UNDELETED}.
-@table @dfn
+@item nnimap-split-fancy
+@cindex splitting, fancy
+@findex nnimap-split-fancy
+@vindex nnimap-split-fancy
-@item server
-This is the machine that is connected to the outside world and where you
-get news and/or mail from.
+It's possible to set @code{nnimap-split-rule} to
+@code{nnmail-split-fancy} if you want to use fancy
+splitting. @xref{Fancy Mail Splitting}.
-@item home machine
-This is the machine that you want to do the actual reading and responding
-on. It is typically not connected to the rest of the world in any way.
+However, to be able to have different fancy split rules for nnmail and
+nnimap back ends you can set @code{nnimap-split-rule} to
+@code{nnimap-split-fancy} and define the nnimap specific fancy split
+rule in @code{nnimap-split-fancy}.
-@item packet
-Something that contains messages and/or commands. There are two kinds
-of packets:
+Example:
-@table @dfn
-@item message packets
-These are packets made at the server, and typically contain lots of
-messages for you to read. These are called @file{SoupoutX.tgz} by
-default, where @var{x} is a number.
+@lisp
+(setq nnimap-split-rule 'nnimap-split-fancy
+ nnimap-split-fancy ...)
+@end lisp
-@item response packets
-These are packets made at the home machine, and typically contains
-replies that you've written. These are called @file{SoupinX.tgz} by
-default, where @var{x} is a number.
+Nnmail equivalent: @code{nnmail-split-fancy}.
@end table
-@end table
+@node Editing IMAP ACLs
+@subsection Editing @sc{imap} ACLs
+@cindex editing imap acls
+@cindex Access Control Lists
+@cindex Editing @sc{imap} ACLs
+@kindex G l
+@findex gnus-group-nnimap-edit-acl
+ACL stands for Access Control List. ACLs are used in @sc{imap} for
+limiting (or enabling) other users access to your mail boxes. Not all
+@sc{imap} servers support this, this function will give an error if it
+doesn't.
-@enumerate
+To edit a ACL for a mailbox, type @kbd{G l}
+(@code{gnus-group-edit-nnimap-acl}) and you'll be presented with a ACL
+editing window with detailed instructions.
-@item
-You log in on the server and create a @sc{soup} packet. You can either
-use a dedicated @sc{soup} thingie (like the @code{awk} program), or you
-can use Gnus to create the packet with its @sc{soup} commands (@kbd{O
-s} and/or @kbd{G s b}; and then @kbd{G s p}) (@pxref{SOUP Commands}).
+Some possible uses:
+@itemize @bullet
@item
-You transfer the packet home. Rail, boat, car or modem will do fine.
-
+Giving "anyone" the "lrs" rights (lookup, read, keep seen/unseen flags)
+on your mailing list mailboxes enables other users on the same server to
+follow the list without subscribing to it.
@item
-You put the packet in your home directory.
+At least with the Cyrus server, you are required to give the user
+"anyone" posting ("p") capabilities to have "plussing" work (that is,
+mail sent to user+mailbox@@domain ending up in the @sc{imap} mailbox
+INBOX.mailbox).
+@end itemize
-@item
-You fire up Gnus on your home machine using the @code{nnsoup} backend as
-the native or secondary server.
+@node Expunging mailboxes
+@subsection Expunging mailboxes
+@cindex expunging
-@item
-You read articles and mail and answer and followup to the things you
-want (@pxref{SOUP Replies}).
+@cindex Expunge
+@cindex Manual expunging
+@kindex G x
+@findex gnus-group-nnimap-expunge
-@item
-You do the @kbd{G s r} command to pack these replies into a @sc{soup}
-packet.
+If you're using the @code{never} setting of @code{nnimap-expunge-on-close},
+you may want the option of expunging all deleted articles in a mailbox
+manually. This is exactly what @kbd{G x} does.
-@item
-You transfer this packet to the server.
+Currently there is no way of showing deleted articles, you can just
+delete them.
-@item
-You use Gnus to mail this packet out with the @kbd{G s s} command.
-@item
-You then repeat until you die.
-@end enumerate
+@node Other Sources
+@section Other Sources
-So you basically have a bipartite system---you use @code{nnsoup} for
-reading and Gnus for packing/sending these @sc{soup} packets.
+Gnus can do more than just read news or mail. The methods described
+below allow Gnus to view directories and files as if they were
+newsgroups.
@menu
-* SOUP Commands:: Commands for creating and sending @sc{soup} packets
-* SOUP Groups:: A backend for reading @sc{soup} packets.
-* SOUP Replies:: How to enable @code{nnsoup} to take over mail and news.
+* Directory Groups:: You can read a directory as if it was a newsgroup.
+* Anything Groups:: Dired? Who needs dired?
+* Document Groups:: Single files can be the basis of a group.
+* SOUP:: Reading @sc{soup} packets ``offline''.
+* Mail-To-News Gateways:: Posting articles via mail-to-news gateways.
@end menu
-@node SOUP Commands
-@subsubsection SOUP Commands
-
-These are commands for creating and manipulating @sc{soup} packets.
-
-@table @kbd
-@item G s b
-@kindex G s b (Group)
-@findex gnus-group-brew-soup
-Pack all unread articles in the current group
-(@code{gnus-group-brew-soup}). This command understands the
-process/prefix convention.
+@node Directory Groups
+@subsection Directory Groups
+@cindex nndir
+@cindex directory groups
-@item G s w
-@kindex G s w (Group)
-@findex gnus-soup-save-areas
-Save all @sc{soup} data files (@code{gnus-soup-save-areas}).
+If you have a directory that has lots of articles in separate files in
+it, you might treat it as a newsgroup. The files have to have numerical
+names, of course.
-@item G s s
-@kindex G s s (Group)
-@findex gnus-soup-send-replies
-Send all replies from the replies packet
-(@code{gnus-soup-send-replies}).
+This might be an opportune moment to mention @code{ange-ftp} (and its
+successor @code{efs}), that most wonderful of all wonderful Emacs
+packages. When I wrote @code{nndir}, I didn't think much about it---a
+back end to read directories. Big deal.
-@item G s p
-@kindex G s p (Group)
-@findex gnus-soup-pack-packet
-Pack all files into a @sc{soup} packet (@code{gnus-soup-pack-packet}).
+@code{ange-ftp} changes that picture dramatically. For instance, if you
+enter the @code{ange-ftp} file name
+@file{/ftp.hpc.uh.edu:/pub/emacs/ding-list/} as the directory name,
+@code{ange-ftp} or @code{efs} will actually allow you to read this
+directory over at @samp{sina} as a newsgroup. Distributed news ahoy!
-@item G s r
-@kindex G s r (Group)
-@findex nnsoup-pack-replies
-Pack all replies into a replies packet (@code{nnsoup-pack-replies}).
+@code{nndir} will use @sc{nov} files if they are present.
-@item O s
-@kindex O s (Summary)
-@findex gnus-soup-add-article
-This summary-mode command adds the current article to a @sc{soup} packet
-(@code{gnus-soup-add-article}). It understands the process/prefix
-convention (@pxref{Process/Prefix}).
+@code{nndir} is a ``read-only'' back end---you can't delete or expire
+articles with this method. You can use @code{nnmh} or @code{nnml} for
+whatever you use @code{nndir} for, so you could switch to any of those
+methods if you feel the need to have a non-read-only @code{nndir}.
-@end table
+@node Anything Groups
+@subsection Anything Groups
+@cindex nneething
-There are a few variables to customize where Gnus will put all these
-thingies:
+From the @code{nndir} back end (which reads a single spool-like
+directory), it's just a hop and a skip to @code{nneething}, which
+pretends that any arbitrary directory is a newsgroup. Strange, but
+true.
-@table @code
+When @code{nneething} is presented with a directory, it will scan this
+directory and assign article numbers to each file. When you enter such
+a group, @code{nneething} must create ``headers'' that Gnus can use.
+After all, Gnus is a newsreader, in case you're forgetting.
+@code{nneething} does this in a two-step process. First, it snoops each
+file in question. If the file looks like an article (i.e., the first
+few lines look like headers), it will use this as the head. If this is
+just some arbitrary file without a head (e.g. a C source file),
+@code{nneething} will cobble up a header out of thin air. It will use
+file ownership, name and date and do whatever it can with these
+elements.
-@item gnus-soup-directory
-@vindex gnus-soup-directory
-Directory where Gnus will save intermediate files while composing
-@sc{soup} packets. The default is @file{~/SoupBrew/}.
+All this should happen automatically for you, and you will be presented
+with something that looks very much like a newsgroup. Totally like a
+newsgroup, to be precise. If you select an article, it will be displayed
+in the article buffer, just as usual.
-@item gnus-soup-replies-directory
-@vindex gnus-soup-replies-directory
-This is what Gnus will use as a temporary directory while sending our
-reply packets. @file{~/SoupBrew/SoupReplies/} is the default.
+If you select a line that represents a directory, Gnus will pop you into
+a new summary buffer for this @code{nneething} group. And so on. You can
+traverse the entire disk this way, if you feel like, but remember that
+Gnus is not dired, really, and does not intend to be, either.
-@item gnus-soup-prefix-file
-@vindex gnus-soup-prefix-file
-Name of the file where Gnus stores the last used prefix. The default is
-@samp{gnus-prefix}.
+There are two overall modes to this action---ephemeral or solid. When
+doing the ephemeral thing (i.e., @kbd{G D} from the group buffer), Gnus
+will not store information on what files you have read, and what files
+are new, and so on. If you create a solid @code{nneething} group the
+normal way with @kbd{G m}, Gnus will store a mapping table between
+article numbers and file names, and you can treat this group like any
+other groups. When you activate a solid @code{nneething} group, you will
+be told how many unread articles it contains, etc., etc.
-@item gnus-soup-packer
-@vindex gnus-soup-packer
-A format string command for packing a @sc{soup} packet. The default is
-@samp{tar cf - %s | gzip > $HOME/Soupout%d.tgz}.
+Some variables:
-@item gnus-soup-unpacker
-@vindex gnus-soup-unpacker
-Format string command for unpacking a @sc{soup} packet. The default is
-@samp{gunzip -c %s | tar xvf -}.
+@table @code
+@item nneething-map-file-directory
+@vindex nneething-map-file-directory
+All the mapping files for solid @code{nneething} groups will be stored
+in this directory, which defaults to @file{~/.nneething/}.
-@item gnus-soup-packet-directory
-@vindex gnus-soup-packet-directory
-Where Gnus will look for reply packets. The default is @file{~/}.
+@item nneething-exclude-files
+@vindex nneething-exclude-files
+All files that match this regexp will be ignored. Nice to use to exclude
+auto-save files and the like, which is what it does by default.
-@item gnus-soup-packet-regexp
-@vindex gnus-soup-packet-regexp
-Regular expression matching @sc{soup} reply packets in
-@code{gnus-soup-packet-directory}.
+@item nneething-include-files
+@vindex nneething-include-files
+Regexp saying what files to include in the group. If this variable is
+non-@code{nil}, only files matching this regexp will be included.
+@item nneething-map-file
+@vindex nneething-map-file
+Name of the map files.
@end table
-@node SOUP Groups
-@subsubsection @sc{soup} Groups
-@cindex nnsoup
-
-@code{nnsoup} is the backend for reading @sc{soup} packets. It will
-read incoming packets, unpack them, and put them in a directory where
-you can read them at leisure.
+@node Document Groups
+@subsection Document Groups
+@cindex nndoc
+@cindex documentation group
+@cindex help group
-These are the variables you can use to customize its behavior:
+@code{nndoc} is a cute little thing that will let you read a single file
+as a newsgroup. Several files types are supported:
@table @code
+@cindex babyl
+@cindex rmail mbox
-@item nnsoup-tmp-directory
-@vindex nnsoup-tmp-directory
-When @code{nnsoup} unpacks a @sc{soup} packet, it does it in this
-directory. (@file{/tmp/} by default.)
-
-@item nnsoup-directory
-@vindex nnsoup-directory
-@code{nnsoup} then moves each message and index file to this directory.
-The default is @file{~/SOUP/}.
-
-@item nnsoup-replies-directory
-@vindex nnsoup-replies-directory
-All replies will be stored in this directory before being packed into a
-reply packet. The default is @file{~/SOUP/replies/"}.
+@item babyl
+The babyl (rmail) mail box.
+@cindex mbox
+@cindex Unix mbox
-@item nnsoup-replies-format-type
-@vindex nnsoup-replies-format-type
-The @sc{soup} format of the replies packets. The default is @samp{?n}
-(rnews), and I don't think you should touch that variable. I probably
-shouldn't even have documented it. Drats! Too late!
+@item mbox
+The standard Unix mbox file.
-@item nnsoup-replies-index-type
-@vindex nnsoup-replies-index-type
-The index type of the replies packet. The default is @samp{?n}, which
-means ``none''. Don't fiddle with this one either!
+@cindex MMDF mail box
+@item mmdf
+The MMDF mail box format.
-@item nnsoup-active-file
-@vindex nnsoup-active-file
-Where @code{nnsoup} stores lots of information. This is not an ``active
-file'' in the @code{nntp} sense; it's an Emacs Lisp file. If you lose
-this file or mess it up in any way, you're dead. The default is
-@file{~/SOUP/active}.
+@item news
+Several news articles appended into a file.
-@item nnsoup-packer
-@vindex nnsoup-packer
-Format string command for packing a reply @sc{soup} packet. The default
-is @samp{tar cf - %s | gzip > $HOME/Soupin%d.tgz}.
+@item rnews
+@cindex rnews batch files
+The rnews batch transport format.
+@cindex forwarded messages
-@item nnsoup-unpacker
-@vindex nnsoup-unpacker
-Format string command for unpacking incoming @sc{soup} packets. The
-default is @samp{gunzip -c %s | tar xvf -}.
+@item forward
+Forwarded articles.
-@item nnsoup-packet-directory
-@vindex nnsoup-packet-directory
-Where @code{nnsoup} will look for incoming packets. The default is
-@file{~/}.
+@item nsmail
+Netscape mail boxes.
-@item nnsoup-packet-regexp
-@vindex nnsoup-packet-regexp
-Regular expression matching incoming @sc{soup} packets. The default is
-@samp{Soupout}.
+@item mime-parts
+MIME multipart messages.
-@item nnsoup-always-save
-@vindex nnsoup-always-save
-If non-@code{nil}, save the replies buffer after each posted message.
+@item standard-digest
+The standard (RFC 1153) digest format.
+@item slack-digest
+Non-standard digest format---matches most things, but does it badly.
@end table
+You can also use the special ``file type'' @code{guess}, which means
+that @code{nndoc} will try to guess what file type it is looking at.
+@code{digest} means that @code{nndoc} should guess what digest type the
+file is.
-@node SOUP Replies
-@subsubsection SOUP Replies
-
-Just using @code{nnsoup} won't mean that your postings and mailings end
-up in @sc{soup} reply packets automagically. You have to work a bit
-more for that to happen.
-
-@findex nnsoup-set-variables
-The @code{nnsoup-set-variables} command will set the appropriate
-variables to ensure that all your followups and replies end up in the
-@sc{soup} system.
+@code{nndoc} will not try to change the file or insert any extra headers into
+it---it will simply, like, let you use the file as the basis for a
+group. And that's it.
-In specific, this is what it does:
-
-@lisp
-(setq message-send-news-function 'nnsoup-request-post)
-(setq message-send-mail-function 'nnsoup-request-mail)
-@end lisp
-
-And that's it, really. If you only want news to go into the @sc{soup}
-system you just use the first line. If you only want mail to be
-@sc{soup}ed you use the second.
-
-
-@node Mail-To-News Gateways
-@subsection Mail-To-News Gateways
-@cindex mail-to-news gateways
-@cindex gateways
+If you have some old archived articles that you want to insert into your
+new & spiffy Gnus mail back end, @code{nndoc} can probably help you with
+that. Say you have an old @file{RMAIL} file with mail that you now want
+to split into your new @code{nnml} groups. You look at that file using
+@code{nndoc} (using the @kbd{G f} command in the group buffer
+(@pxref{Foreign Groups})), set the process mark on all the articles in
+the buffer (@kbd{M P b}, for instance), and then re-spool (@kbd{B r})
+using @code{nnml}. If all goes well, all the mail in the @file{RMAIL}
+file is now also stored in lots of @code{nnml} directories, and you can
+delete that pesky @file{RMAIL} file. If you have the guts!
-If your local @code{nntp} server doesn't allow posting, for some reason
-or other, you can post using one of the numerous mail-to-news gateways.
-The @code{nngateway} backend provides the interface.
+Virtual server variables:
-Note that you can't read anything from this backend---it can only be
-used to post with.
+@table @code
+@item nndoc-article-type
+@vindex nndoc-article-type
+This should be one of @code{mbox}, @code{babyl}, @code{digest},
+@code{news}, @code{rnews}, @code{mmdf}, @code{forward}, @code{rfc934},
+@code{rfc822-forward}, @code{mime-parts}, @code{standard-digest},
+@code{slack-digest}, @code{clari-briefs}, @code{nsmail},
+@code{outlook}, @code{oe-dbx}, and @code{mailman} or @code{guess}.
-Server variables:
+@item nndoc-post-type
+@vindex nndoc-post-type
+This variable says whether Gnus is to consider the group a news group or
+a mail group. There are two valid values: @code{mail} (the default)
+and @code{news}.
+@end table
-@table @code
-@item nngateway-address
-@vindex nngateway-address
-This is the address of the mail-to-news gateway.
+@menu
+* Document Server Internals:: How to add your own document types.
+@end menu
-@item nngateway-header-transformation
-@vindex nngateway-header-transformation
-News headers often have to be transformed in some odd way or other
-for the mail-to-news gateway to accept it. This variable says what
-transformation should be called, and defaults to
-@code{nngateway-simple-header-transformation}. The function is called
-narrowed to the headers to be transformed and with one parameter---the
-gateway address.
-This default function just inserts a new @code{To} header based on the
-@code{Newsgroups} header and the gateway address.
-For instance, an article with this @code{Newsgroups} header:
+@node Document Server Internals
+@subsubsection Document Server Internals
-@example
-Newsgroups: alt.religion.emacs
-@end example
+Adding new document types to be recognized by @code{nndoc} isn't
+difficult. You just have to whip up a definition of what the document
+looks like, write a predicate function to recognize that document type,
+and then hook into @code{nndoc}.
-will get this @code{From} header inserted:
+First, here's an example document type definition:
@example
-To: alt-religion-emacs@@GATEWAY
+(mmdf
+ (article-begin . "^\^A\^A\^A\^A\n")
+ (body-end . "^\^A\^A\^A\^A\n"))
@end example
-The following pre-defined functions exist:
+The definition is simply a unique @dfn{name} followed by a series of
+regexp pseudo-variable settings. Below are the possible
+variables---don't be daunted by the number of variables; most document
+types can be defined with very few settings:
-@findex nngateway-simple-header-transformation
@table @code
+@item first-article
+If present, @code{nndoc} will skip past all text until it finds
+something that match this regexp. All text before this will be
+totally ignored.
-@item nngateway-simple-header-transformation
-Creates a @code{To} header that looks like
-@var{newsgroup}@@@code{nngateway-address}.
-
-@findex nngateway-mail2news-header-transformation
-
-@item nngateway-mail2news-header-transformation
-Creates a @code{To} header that looks like
-@code{nngateway-address}.
-
-Here's an example:
-
-@lisp
-(setq gnus-post-method
- '(nngateway "mail2news@@replay.com"
- (nngateway-header-transformation
- nngateway-mail2news-header-transformation)))
-@end lisp
+@item article-begin
+This setting has to be present in all document type definitions. It
+says what the beginning of each article looks like.
-@end table
+@item head-begin-function
+If present, this should be a function that moves point to the head of
+the article.
+@item nndoc-head-begin
+If present, this should be a regexp that matches the head of the
+article.
-@end table
+@item nndoc-head-end
+This should match the end of the head of the article. It defaults to
+@samp{^$}---the empty line.
-So, to use this, simply say something like:
+@item body-begin-function
+If present, this function should move point to the beginning of the body
+of the article.
-@lisp
-(setq gnus-post-method '(nngateway "GATEWAY.ADDRESS"))
-@end lisp
+@item body-begin
+This should match the beginning of the body of the article. It defaults
+to @samp{^\n}.
+@item body-end-function
+If present, this function should move point to the end of the body of
+the article.
+@item body-end
+If present, this should match the end of the body of the article.
-@node IMAP
-@subsection @sc{imap}
-@cindex nnimap
-@cindex @sc{imap}
+@item file-end
+If present, this should match the end of the file. All text after this
+regexp will be totally ignored.
-@sc{imap} is a network protocol for reading mail (or news, or ...),
-think of it as a modernized @sc{nntp}. Connecting to a @sc{imap}
-server is much similar to connecting to a news server, you just
-specify the network address of the server.
+@end table
-@sc{imap} has two properties. First, @sc{imap} can do everything that
-POP can, it can hence be viewed as POP++. Secondly, @sc{imap} is a
-mail storage protocol, similar to @sc{nntp} being a news storage
-protocol. (@sc{imap} offers more features than @sc{nntp} because news
-is more or less read-only whereas mail is read-write.)
+So, using these variables @code{nndoc} is able to dissect a document
+file into a series of articles, each with a head and a body. However, a
+few more variables are needed since not all document types are all that
+news-like---variables needed to transform the head or the body into
+something that's palatable for Gnus:
-If you want to use @sc{imap} as POP++, use an imap entry in
-mail-sources. With this, Gnus will fetch mails from the @sc{imap}
-server and store them on the local disk. This is not the usage
-described in this section. @xref{Mail Sources}.
+@table @code
+@item prepare-body-function
+If present, this function will be called when requesting an article. It
+will be called with point at the start of the body, and is useful if the
+document has encoded some parts of its contents.
-If you want to use @sc{imap} as a mail storage protocol, use an nnimap
-entry in gnus-secondary-select-methods. With this, Gnus will
-manipulate mails stored on the @sc{imap} server. This is the kind of
-usage explained in this section.
+@item article-transform-function
+If present, this function is called when requesting an article. It's
+meant to be used for more wide-ranging transformation of both head and
+body of the article.
-A server configuration in @code{~/.gnus} with a few @sc{imap} servers
-might look something like this:
+@item generate-head-function
+If present, this function is called to generate a head that Gnus can
+understand. It is called with the article number as a parameter, and is
+expected to generate a nice head for the article in question. It is
+called when requesting the headers of all articles.
-@lisp
-(setq gnus-secondary-select-methods
- '((nnimap "simpleserver") ; no special configuration
- ; perhaps a ssh port forwarded server:
- (nnimap "dolk"
- (nnimap-address "localhost")
- (nnimap-server-port 1430))
- ; a UW server running on localhost
- (nnimap "barbar"
- (nnimap-server-port 143)
- (nnimap-address "localhost")
- (nnimap-list-pattern ("INBOX" "mail/*")))
- ; anonymous public cyrus server:
- (nnimap "cyrus.andrew.cmu.edu"
- (nnimap-authenticator anonymous)
- (nnimap-list-pattern "archive.*")
- (nnimap-stream network))
- ; a ssl server on a non-standard port:
- (nnimap "vic20"
- (nnimap-address "vic20.somewhere.com")
- (nnimap-server-port 9930)
- (nnimap-stream ssl))))
-@end lisp
+@end table
-The following variables can be used to create a virtual @code{nnimap}
-server:
+Let's look at the most complicated example I can come up with---standard
+digests:
-@table @code
+@example
+(standard-digest
+ (first-article . ,(concat "^" (make-string 70 ?-) "\n\n+"))
+ (article-begin . ,(concat "\n\n" (make-string 30 ?-) "\n\n+"))
+ (prepare-body-function . nndoc-unquote-dashes)
+ (body-end-function . nndoc-digest-body-end)
+ (head-end . "^ ?$")
+ (body-begin . "^ ?\n")
+ (file-end . "^End of .*digest.*[0-9].*\n\\*\\*\\|^End of.*Digest *$")
+ (subtype digest guess))
+@end example
-@item nnimap-address
-@vindex nnimap-address
+We see that all text before a 70-width line of dashes is ignored; all
+text after a line that starts with that @samp{^End of} is also ignored;
+each article begins with a 30-width line of dashes; the line separating
+the head from the body may contain a single space; and that the body is
+run through @code{nndoc-unquote-dashes} before being delivered.
-The address of the remote @sc{imap} server. Defaults to the virtual
-server name if not specified.
+To hook your own document definition into @code{nndoc}, use the
+@code{nndoc-add-type} function. It takes two parameters---the first is
+the definition itself and the second (optional) parameter says where in
+the document type definition alist to put this definition. The alist is
+traversed sequentially, and @code{nndoc-TYPE-type-p} is called for a given type @code{TYPE}. So @code{nndoc-mmdf-type-p} is called to see whether a document
+is of @code{mmdf} type, and so on. These type predicates should return
+@code{nil} if the document is not of the correct type; @code{t} if it is
+of the correct type; and a number if the document might be of the
+correct type. A high number means high probability; a low number means
+low probability with @samp{0} being the lowest valid number.
-@item nnimap-server-port
-@vindex nnimap-server-port
-Port on server to contact. Defaults to port 143, or 993 for SSL.
-Note that this should be a integer, example server specification:
+@node SOUP
+@subsection SOUP
+@cindex SOUP
+@cindex offline
-@lisp
-(nnimap "mail.server.com"
- (nnimap-server-port 4711))
-@end lisp
+In the PC world people often talk about ``offline'' newsreaders. These
+are thingies that are combined reader/news transport monstrosities.
+With built-in modem programs. Yecchh!
-@item nnimap-list-pattern
-@vindex nnimap-list-pattern
-String or list of strings of mailboxes to limit available groups to.
-This is used when the server has very many mailboxes and you're only
-interested in a few -- some servers export your home directory via
-@sc{imap}, you'll probably want to limit the mailboxes to those in
-@file{~/Mail/*} then.
+Of course, us Unix Weenie types of human beans use things like
+@code{uucp} and, like, @code{nntpd} and set up proper news and mail
+transport things like Ghod intended. And then we just use normal
+newsreaders.
-The string can also be a cons of REFERENCE and the string as above, what
-REFERENCE is used for is server specific, but on the University of
-Washington server it's a directory that will be concatenated with the
-mailbox.
+However, it can sometimes be convenient to do something that's a bit
+easier on the brain if you have a very slow modem, and you're not really
+that interested in doing things properly.
-Example server specification:
+A file format called @sc{soup} has been developed for transporting news
+and mail from servers to home machines and back again. It can be a bit
+fiddly.
-@lisp
-(nnimap "mail.server.com"
- (nnimap-list-pattern ("INBOX" "Mail/*" "alt.sex.*"
- ("~friend/Mail/" . "list/*"))))
-@end lisp
+First some terminology:
-@item nnimap-stream
-@vindex nnimap-stream
-The type of stream used to connect to your server. By default, nnimap
-will detect and automatically use all of the below, with the exception
-of SSL. (SSL is being replaced by STARTTLS, which can be automatically
-detected, but it's not widely deployed yet).
+@table @dfn
-Example server specification:
+@item server
+This is the machine that is connected to the outside world and where you
+get news and/or mail from.
-@lisp
-(nnimap "mail.server.com"
- (nnimap-stream ssl))
-@end lisp
+@item home machine
+This is the machine that you want to do the actual reading and responding
+on. It is typically not connected to the rest of the world in any way.
-Please note that the value of @code{nnimap-stream} is a symbol!
+@item packet
+Something that contains messages and/or commands. There are two kinds
+of packets:
-@itemize @bullet
-@item
-@dfn{gssapi:} Connect with GSSAPI (usually kerberos 5). Require the
-@samp{imtest} program.
-@item
-@dfn{kerberos4:} Connect with kerberos 4. Require the @samp{imtest} program.
-@item
-@dfn{starttls:} Connect via the STARTTLS extension (similar to
-SSL). Require the external library @samp{starttls.el} and program
-@samp{starttls}.
-@item
-@dfn{ssl:} Connect through SSL. Require OpenSSL (the
-program @samp{openssl}) or SSLeay (@samp{s_client}).
-@item
-@dfn{shell:} Use a shell command to start @sc{imap} connection.
-@item
-@dfn{network:} Plain, TCP/IP network connection.
-@end itemize
+@table @dfn
+@item message packets
+These are packets made at the server, and typically contain lots of
+messages for you to read. These are called @file{SoupoutX.tgz} by
+default, where @var{x} is a number.
-@vindex imap-kerberos4-program
-The @samp{imtest} program is shipped with Cyrus IMAPD, nnimap support
-both @samp{imtest} version 1.5.x and version 1.6.x. The variable
-@code{imap-kerberos4-program} contain parameters to pass to the imtest
-program.
+@item response packets
+These are packets made at the home machine, and typically contains
+replies that you've written. These are called @file{SoupinX.tgz} by
+default, where @var{x} is a number.
-@vindex imap-ssl-program
-For SSL connections, the OpenSSL program is available from
-@uref{http://www.openssl.org/}. OpenSSL was formerly known as SSLeay,
-and nnimap support it too - altough the most recent versions of
-SSLeay, 0.9.x, are known to have serious bugs making it
-useless. Earlier versions, especially 0.8.x, of SSLeay are known to
-work. The variable @code{imap-ssl-program} contain parameters to pass
-to OpenSSL/SSLeay.
+@end table
-@vindex imap-shell-program
-@vindex imap-shell-host
-For @sc{imap} connections using the @code{shell} stream, the variable
-@code{imap-shell-program} specify what program to call.
+@end table
-@item nnimap-authenticator
-@vindex nnimap-authenticator
-The authenticator used to connect to the server. By default, nnimap
-will use the most secure authenticator your server is capable of.
+@enumerate
-Example server specification:
+@item
+You log in on the server and create a @sc{soup} packet. You can either
+use a dedicated @sc{soup} thingie (like the @code{awk} program), or you
+can use Gnus to create the packet with its @sc{soup} commands (@kbd{O
+s} and/or @kbd{G s b}; and then @kbd{G s p}) (@pxref{SOUP Commands}).
-@lisp
-(nnimap "mail.server.com"
- (nnimap-authenticator anonymous))
-@end lisp
+@item
+You transfer the packet home. Rail, boat, car or modem will do fine.
-Please note that the value of @code{nnimap-authenticator} is a symbol!
+@item
+You put the packet in your home directory.
-@itemize @bullet
@item
-@dfn{gssapi:} GSSAPI (usually kerberos 5) authentication. Require
-external program @code{imtest}.
+You fire up Gnus on your home machine using the @code{nnsoup} back end as
+the native or secondary server.
+
@item
-@dfn{kerberos4:} Kerberos authentication. Require external program
-@code{imtest}.
+You read articles and mail and answer and followup to the things you
+want (@pxref{SOUP Replies}).
+
@item
-@dfn{digest-md5:} Encrypted username/password via DIGEST-MD5. Require
-external library @code{digest-md5.el}.
+You do the @kbd{G s r} command to pack these replies into a @sc{soup}
+packet.
+
@item
-@dfn{cram-md5:} Encrypted username/password via CRAM-MD5.
+You transfer this packet to the server.
+
@item
-@dfn{login:} Plain-text username/password via LOGIN.
+You use Gnus to mail this packet out with the @kbd{G s s} command.
+
@item
-@dfn{anonymous:} Login as `anonymous', supplying your emailadress as password.
-@end itemize
+You then repeat until you die.
-@item nnimap-expunge-on-close
-@cindex Expunging
-@vindex nnimap-expunge-on-close
-Unlike Parmenides the @sc{imap} designers has decided that things that
-doesn't exist actually does exist. More specifically, @sc{imap} has
-this concept of marking articles @code{Deleted} which doesn't actually
-delete them, and this (marking them @code{Deleted}, that is) is what
-nnimap does when you delete a article in Gnus (with @kbd{G DEL} or
-similar).
+@end enumerate
-Since the articles aren't really removed when we mark them with the
-@code{Deleted} flag we'll need a way to actually delete them. Feel like
-running in circles yet?
+So you basically have a bipartite system---you use @code{nnsoup} for
+reading and Gnus for packing/sending these @sc{soup} packets.
-Traditionally, nnimap has removed all articles marked as @code{Deleted}
-when closing a mailbox but this is now configurable by this server
-variable.
+@menu
+* SOUP Commands:: Commands for creating and sending @sc{soup} packets
+* SOUP Groups:: A back end for reading @sc{soup} packets.
+* SOUP Replies:: How to enable @code{nnsoup} to take over mail and news.
+@end menu
-The possible options are:
-@table @code
+@node SOUP Commands
+@subsubsection SOUP Commands
-@item always
-The default behavior, delete all articles marked as "Deleted" when
-closing a mailbox.
-@item never
-Never actually delete articles. Currently there is no way of showing
-the articles marked for deletion in nnimap, but other @sc{imap} clients
-may allow you to do this. If you ever want to run the EXPUNGE command
-manually, @xref{Expunging mailboxes}.
-@item ask
-When closing mailboxes, nnimap will ask if you wish to expunge deleted
-articles or not.
+These are commands for creating and manipulating @sc{soup} packets.
-@end table
+@table @kbd
+@item G s b
+@kindex G s b (Group)
+@findex gnus-group-brew-soup
+Pack all unread articles in the current group
+(@code{gnus-group-brew-soup}). This command understands the
+process/prefix convention.
-@item nnimap-authinfo-file
-@vindex nnimap-authinfo-file
+@item G s w
+@kindex G s w (Group)
+@findex gnus-soup-save-areas
+Save all @sc{soup} data files (@code{gnus-soup-save-areas}).
-A file containing credentials used to log in on servers. The format
-is (almost) the same as the @code{ftp} @file{~/.netrc} file. See
-`nntp-authinfo-file' for exact syntax.
+@item G s s
+@kindex G s s (Group)
+@findex gnus-soup-send-replies
+Send all replies from the replies packet
+(@code{gnus-soup-send-replies}).
-A file containing credentials used to log in on servers. The format is
-(almost) the same as the @code{ftp} @file{~/.netrc} file. See the
-variable @code{nntp-authinfo-file} for exact syntax; also see
-@xref{NNTP}.
+@item G s p
+@kindex G s p (Group)
+@findex gnus-soup-pack-packet
+Pack all files into a @sc{soup} packet (@code{gnus-soup-pack-packet}).
+
+@item G s r
+@kindex G s r (Group)
+@findex nnsoup-pack-replies
+Pack all replies into a replies packet (@code{nnsoup-pack-replies}).
+
+@item O s
+@kindex O s (Summary)
+@findex gnus-soup-add-article
+This summary-mode command adds the current article to a @sc{soup} packet
+(@code{gnus-soup-add-article}). It understands the process/prefix
+convention (@pxref{Process/Prefix}).
@end table
-@menu
-* Splitting in IMAP:: Splitting mail with nnimap.
-* Editing IMAP ACLs:: Limiting/enabling other users access to a mailbox.
-* Expunging mailboxes:: Equivalent of a "compress mailbox" button.
-@end menu
+There are a few variables to customize where Gnus will put all these
+thingies:
+
+@table @code
+@item gnus-soup-directory
+@vindex gnus-soup-directory
+Directory where Gnus will save intermediate files while composing
+@sc{soup} packets. The default is @file{~/SoupBrew/}.
-@node Splitting in IMAP
-@subsubsection Splitting in @sc{imap}
-@cindex splitting imap mail
+@item gnus-soup-replies-directory
+@vindex gnus-soup-replies-directory
+This is what Gnus will use as a temporary directory while sending our
+reply packets. @file{~/SoupBrew/SoupReplies/} is the default.
-Splitting is something Gnus users has loved and used for years, and now
-the rest of the world is catching up. Yeah, dream on, not many
-@sc{imap} server has server side splitting and those that have splitting
-seem to use some non-standard protocol. This means that @sc{imap}
-support for Gnus has to do it's own splitting.
+@item gnus-soup-prefix-file
+@vindex gnus-soup-prefix-file
+Name of the file where Gnus stores the last used prefix. The default is
+@samp{gnus-prefix}.
-And it does.
+@item gnus-soup-packer
+@vindex gnus-soup-packer
+A format string command for packing a @sc{soup} packet. The default is
+@samp{tar cf - %s | gzip > $HOME/Soupout%d.tgz}.
-Here are the variables of interest:
+@item gnus-soup-unpacker
+@vindex gnus-soup-unpacker
+Format string command for unpacking a @sc{soup} packet. The default is
+@samp{gunzip -c %s | tar xvf -}.
-@table @code
+@item gnus-soup-packet-directory
+@vindex gnus-soup-packet-directory
+Where Gnus will look for reply packets. The default is @file{~/}.
-@item nnimap-split-crosspost
-@cindex splitting, crosspost
-@cindex crosspost
-@vindex nnimap-split-crosspost
+@item gnus-soup-packet-regexp
+@vindex gnus-soup-packet-regexp
+Regular expression matching @sc{soup} reply packets in
+@code{gnus-soup-packet-directory}.
-If non-nil, do crossposting if several split methods match the mail. If
-nil, the first match in @code{nnimap-split-rule} found will be used.
+@end table
-Nnmail equivalent: @code{nnmail-crosspost}.
-@item nnimap-split-inbox
-@cindex splitting, inbox
-@cindex inbox
-@vindex nnimap-split-inbox
+@node SOUP Groups
+@subsubsection @sc{soup} Groups
+@cindex nnsoup
-A string or a list of strings that gives the name(s) of @sc{imap}
-mailboxes to split from. Defaults to nil, which means that splitting is
-disabled!
+@code{nnsoup} is the back end for reading @sc{soup} packets. It will
+read incoming packets, unpack them, and put them in a directory where
+you can read them at leisure.
-@lisp
-(setq nnimap-split-inbox
- '("INBOX" ("~/friend/Mail" . "lists/*") "lists.imap"))
-@end lisp
+These are the variables you can use to customize its behavior:
-No nnmail equivalent.
+@table @code
-@item nnimap-split-rule
-@cindex Splitting, rules
-@vindex nnimap-split-rule
+@item nnsoup-tmp-directory
+@vindex nnsoup-tmp-directory
+When @code{nnsoup} unpacks a @sc{soup} packet, it does it in this
+directory. (@file{/tmp/} by default.)
-New mail found in @code{nnimap-split-inbox} will be split according to
-this variable.
+@item nnsoup-directory
+@vindex nnsoup-directory
+@code{nnsoup} then moves each message and index file to this directory.
+The default is @file{~/SOUP/}.
-This variable contains a list of lists, where the first element in the
-sublist gives the name of the @sc{imap} mailbox to move articles
-matching the regexp in the second element in the sublist. Got that?
-Neither did I, we need examples.
+@item nnsoup-replies-directory
+@vindex nnsoup-replies-directory
+All replies will be stored in this directory before being packed into a
+reply packet. The default is @file{~/SOUP/replies/"}.
-@lisp
-(setq nnimap-split-rule
- '(("INBOX.nnimap" "^Sender: owner-nnimap@@vic20.globalcom.se")
- ("INBOX.junk" "^Subject:.*MAKE MONEY")
- ("INBOX.private" "")))
-@end lisp
+@item nnsoup-replies-format-type
+@vindex nnsoup-replies-format-type
+The @sc{soup} format of the replies packets. The default is @samp{?n}
+(rnews), and I don't think you should touch that variable. I probably
+shouldn't even have documented it. Drats! Too late!
-This will put all articles from the nnimap mailing list into mailbox
-INBOX.nnimap, all articles containing MAKE MONEY in the Subject: line
-into INBOX.junk and everything else in INBOX.private.
+@item nnsoup-replies-index-type
+@vindex nnsoup-replies-index-type
+The index type of the replies packet. The default is @samp{?n}, which
+means ``none''. Don't fiddle with this one either!
-The first string may contain `\\1' forms, like the ones used by
-replace-match to insert sub-expressions from the matched text. For
-instance:
+@item nnsoup-active-file
+@vindex nnsoup-active-file
+Where @code{nnsoup} stores lots of information. This is not an ``active
+file'' in the @code{nntp} sense; it's an Emacs Lisp file. If you lose
+this file or mess it up in any way, you're dead. The default is
+@file{~/SOUP/active}.
+
+@item nnsoup-packer
+@vindex nnsoup-packer
+Format string command for packing a reply @sc{soup} packet. The default
+is @samp{tar cf - %s | gzip > $HOME/Soupin%d.tgz}.
+
+@item nnsoup-unpacker
+@vindex nnsoup-unpacker
+Format string command for unpacking incoming @sc{soup} packets. The
+default is @samp{gunzip -c %s | tar xvf -}.
+
+@item nnsoup-packet-directory
+@vindex nnsoup-packet-directory
+Where @code{nnsoup} will look for incoming packets. The default is
+@file{~/}.
-@lisp
-("INBOX.lists.\\1" "^Sender: owner-\\([a-z-]+\\)@@")
-@end lisp
+@item nnsoup-packet-regexp
+@vindex nnsoup-packet-regexp
+Regular expression matching incoming @sc{soup} packets. The default is
+@samp{Soupout}.
-The second element can also be a function. In that case, it will be
-called with the first element of the rule as the argument, in a buffer
-containing the headers of the article. It should return a non-nil value
-if it thinks that the mail belongs in that group.
+@item nnsoup-always-save
+@vindex nnsoup-always-save
+If non-@code{nil}, save the replies buffer after each posted message.
-Nnmail users might recollect that the last regexp had to be empty to
-match all articles (like in the example above). This is not required in
-nnimap. Articles not matching any of the regexps will not be moved out
-of your inbox. (This might affect performance if you keep lots of
-unread articles in your inbox, since the splitting code would go over
-them every time you fetch new mail.)
+@end table
-These rules are processed from the beginning of the alist toward the
-end. The first rule to make a match will "win", unless you have
-crossposting enabled. In that case, all matching rules will "win".
-This variable can also have a function as its value, the function will
-be called with the headers narrowed and should return a group where it
-thinks the article should be split to. See @code{nnimap-split-fancy}.
+@node SOUP Replies
+@subsubsection SOUP Replies
+
+Just using @code{nnsoup} won't mean that your postings and mailings end
+up in @sc{soup} reply packets automagically. You have to work a bit
+more for that to happen.
-The splitting code tries to create mailboxes if it need too.
+@findex nnsoup-set-variables
+The @code{nnsoup-set-variables} command will set the appropriate
+variables to ensure that all your followups and replies end up in the
+@sc{soup} system.
-To allow for different split rules on different virtual servers, and
-even different split rules in different inboxes on the same server,
-the syntax of this variable have been extended along the lines of:
+In specific, this is what it does:
@lisp
-(setq nnimap-split-rule
- '(("my1server" (".*" (("ding" "ding@@gnus.org")
- ("junk" "From:.*Simon")))
- ("my2server" ("INBOX" nnimap-split-fancy))
- ("my[34]server" (".*" (("private" "To:.*Simon")
- ("junk" my-junk-func)))))
+(setq message-send-news-function 'nnsoup-request-post)
+(setq message-send-mail-function 'nnsoup-request-mail)
@end lisp
-The virtual server name is in fact a regexp, so that the same rules
-may apply to several servers. In the example, the servers
-@code{my3server} and @code{my4server} both use the same rules.
-Similarly, the inbox string is also a regexp. The actual splitting
-rules are as before, either a function, or a list with group/regexp or
-group/function elements.
+And that's it, really. If you only want news to go into the @sc{soup}
+system you just use the first line. If you only want mail to be
+@sc{soup}ed you use the second.
-Nnmail equivalent: @code{nnmail-split-methods}.
-@item nnimap-split-predicate
-@cindex splitting
-@vindex nnimap-split-predicate
+@node Mail-To-News Gateways
+@subsection Mail-To-News Gateways
+@cindex mail-to-news gateways
+@cindex gateways
-Mail matching this predicate in @code{nnimap-split-inbox} will be
-split, it is a string and the default is @samp{UNSEEN UNDELETED}.
+If your local @code{nntp} server doesn't allow posting, for some reason
+or other, you can post using one of the numerous mail-to-news gateways.
+The @code{nngateway} back end provides the interface.
-This might be useful if you use another @sc{imap} client to read mail in
-your inbox but would like Gnus to split all articles in the inbox
-regardless of readedness. Then you might change this to
-@samp{UNDELETED}.
+Note that you can't read anything from this back end---it can only be
+used to post with.
-@item nnimap-split-fancy
-@cindex splitting, fancy
-@findex nnimap-split-fancy
-@vindex nnimap-split-fancy
+Server variables:
-It's possible to set @code{nnimap-split-rule} to
-@code{nnmail-split-fancy} if you want to use fancy
-splitting. @xref{Fancy Mail Splitting}.
+@table @code
+@item nngateway-address
+@vindex nngateway-address
+This is the address of the mail-to-news gateway.
-However, to be able to have different fancy split rules for nnmail and
-nnimap backends you can set @code{nnimap-split-rule} to
-@code{nnimap-split-fancy} and define the nnimap specific fancy split
-rule in @code{nnimap-split-fancy}.
+@item nngateway-header-transformation
+@vindex nngateway-header-transformation
+News headers often have to be transformed in some odd way or other
+for the mail-to-news gateway to accept it. This variable says what
+transformation should be called, and defaults to
+@code{nngateway-simple-header-transformation}. The function is called
+narrowed to the headers to be transformed and with one parameter---the
+gateway address.
-Example:
+This default function just inserts a new @code{To} header based on the
+@code{Newsgroups} header and the gateway address.
+For instance, an article with this @code{Newsgroups} header:
-@lisp
-(setq nnimap-split-rule 'nnimap-split-fancy
- nnimap-split-fancy ...)
-@end lisp
+@example
+Newsgroups: alt.religion.emacs
+@end example
-Nnmail equivalent: @code{nnmail-split-fancy}.
+will get this @code{From} header inserted:
-@end table
+@example
+To: alt-religion-emacs@@GATEWAY
+@end example
-@node Editing IMAP ACLs
-@subsubsection Editing @sc{imap} ACLs
-@cindex editing imap acls
-@cindex Access Control Lists
-@cindex Editing @sc{imap} ACLs
-@kindex G l
-@findex gnus-group-nnimap-edit-acl
+The following pre-defined functions exist:
-ACL stands for Access Control List. ACLs are used in @sc{imap} for
-limiting (or enabling) other users access to your mail boxes. Not all
-@sc{imap} servers support this, this function will give an error if it
-doesn't.
+@findex nngateway-simple-header-transformation
+@table @code
-To edit a ACL for a mailbox, type @kbd{G l}
-(@code{gnus-group-edit-nnimap-acl}) and you'll be presented with a ACL
-editing window with detailed instructions.
+@item nngateway-simple-header-transformation
+Creates a @code{To} header that looks like
+@var{newsgroup}@@@code{nngateway-address}.
-Some possible uses:
+@findex nngateway-mail2news-header-transformation
-@itemize @bullet
-@item
-Giving "anyone" the "lrs" rights (lookup, read, keep seen/unseen flags)
-on your mailing list mailboxes enables other users on the same server to
-follow the list without subscribing to it.
-@item
-At least with the Cyrus server, you are required to give the user
-"anyone" posting ("p") capabilities to have "plussing" work (that is,
-mail sent to user+mailbox@@domain ending up in the @sc{imap} mailbox
-INBOX.mailbox).
-@end itemize
+@item nngateway-mail2news-header-transformation
+Creates a @code{To} header that looks like
+@code{nngateway-address}.
-@node Expunging mailboxes
-@subsubsection Expunging mailboxes
-@cindex expunging
+Here's an example:
-@cindex Expunge
-@cindex Manual expunging
-@kindex G x
-@findex gnus-group-nnimap-expunge
+@lisp
+(setq gnus-post-method
+ '(nngateway
+ "mail2news@@replay.com"
+ (nngateway-header-transformation
+ nngateway-mail2news-header-transformation)))
+@end lisp
-If you're using the @code{never} setting of @code{nnimap-expunge-close},
-you may want the option of expunging all deleted articles in a mailbox
-manually. This is exactly what @kbd{G x} does.
+@end table
-Currently there is no way of showing deleted articles, you can just
-delete them.
+
+@end table
+
+So, to use this, simply say something like:
+
+@lisp
+(setq gnus-post-method '(nngateway "GATEWAY.ADDRESS"))
+@end lisp
groups.
@menu
-* Virtual Groups:: Combining articles from many groups.
-* Kibozed Groups:: Looking through parts of the newsfeed for articles.
+* Virtual Groups:: Combining articles from many groups.
+* Kibozed Groups:: Looking through parts of the newsfeed for articles.
@end menu
@code{nnvirtual} can have both mail and news groups as component groups.
When responding to articles in @code{nnvirtual} groups, @code{nnvirtual}
-has to ask the backend of the component group the article comes from
-whether it is a news or mail backend. However, when you do a @kbd{^},
-there is typically no sure way for the component backend to know this,
+has to ask the back end of the component group the article comes from
+whether it is a news or mail back end. However, when you do a @kbd{^},
+there is typically no sure way for the component back end to know this,
and in that case @code{nnvirtual} tells Gnus that the article came from a
-not-news backend. (Just to be on the safe side.)
+not-news back end. (Just to be on the safe side.)
-@kbd{C-c C-t} in the message buffer will insert the @code{Newsgroups}
+@kbd{C-c C-n} in the message buffer will insert the @code{Newsgroups}
line from the article you respond to in these cases.
@cindex kibozing
@dfn{Kibozing} is defined by @sc{oed} as ``grepping through (parts of)
-the news feed''. @code{nnkiboze} is a backend that will do this for
+the news feed''. @code{nnkiboze} is a back end that will do this for
you. Oh joy! Now you can grind any @sc{nntp} server down to a halt
with useless requests! Oh happiness!
Of course, to use it as such, you have to learn a few new commands.
@menu
-* Agent Basics:: How it all is supposed to work.
-* Agent Categories:: How to tell the Gnus Agent what to download.
-* Agent Commands:: New commands for all the buffers.
-* Agent Expiry:: How to make old articles go away.
-* Agent and IMAP:: How to use the Agent with IMAP.
-* Outgoing Messages:: What happens when you post/mail something?
-* Agent Variables:: Customizing is fun.
-* Example Setup:: An example @file{.gnus.el} file for offline people.
-* Batching Agents:: How to fetch news from a @code{cron} job.
-* Agent Caveats:: What you think it'll do and what it does.
+* Agent Basics:: How it all is supposed to work.
+* Agent Categories:: How to tell the Gnus Agent what to download.
+* Agent Commands:: New commands for all the buffers.
+* Agent Expiry:: How to make old articles go away.
+* Agent and IMAP:: How to use the Agent with IMAP.
+* Outgoing Messages:: What happens when you post/mail something?
+* Agent Variables:: Customizing is fun.
+* Example Setup:: An example @file{.gnus.el} file for offline people.
+* Batching Agents:: How to fetch news from a @code{cron} job.
+* Agent Caveats:: What you think it'll do and what it does.
@end menu
@item
Decide which servers should be covered by the Agent. If you have a mail
-backend, it would probably be nonsensical to have it covered by the
+back end, it would probably be nonsensical to have it covered by the
Agent. Go to the server buffer (@kbd{^} in the group buffer) and press
@kbd{J a} the server (or servers) that you wish to have covered by the
Agent (@pxref{Server Agent Commands}). This will typically be only the
managing categories.
@menu
-* Category Syntax:: What a category looks like.
-* Category Buffer:: A buffer for maintaining categories.
-* Category Variables:: Customize'r'Us.
+* Category Syntax:: What a category looks like.
+* Category Buffer:: A buffer for maintaining categories.
+* Category Variables:: Customize'r'Us.
@end menu
@subsection Agent Commands
All the Gnus Agent commands are on the @kbd{J} submap. The @kbd{J j}
-(@code{gnus-agent-toggle-plugged} command works in all modes, and
+(@code{gnus-agent-toggle-plugged}) command works in all modes, and
toggles the plugged/unplugged state of the Gnus Agent.
@item J S
@kindex J S (Agent Group)
-@findex gnus-group-send-drafts
-Send all sendable messages in the draft group
-(@code{gnus-group-send-drafts}). @xref{Drafts}.
+@findex gnus-group-send-queue
+Send all sendable messages in the queue group
+(@code{gnus-group-send-queue}). @xref{Drafts}.
@item J a
@kindex J a (Agent Group)
@findex gnus-agent-catchup
Mark all undownloaded articles as read (@code{gnus-agent-catchup}).
+@item J u
+@kindex J u (Agent Summary)
+@findex gnus-agent-summary-fetch-group
+Download all downloadable articles in the current group
+(@code{gnus-agent-summary-fetch-group}).
+
@end table
@node Agent and IMAP
@subsection Agent and IMAP
-The Agent work with any Gnus backend, including nnimap. However,
+The Agent work with any Gnus back end, including nnimap. However,
since there are some conceptual differences between @sc{nntp} and
@sc{imap}, this section (should) provide you with some information to
make Gnus Agent work smoother as a @sc{imap} Disconnected Mode client.
silently to help keep the sizes of the score files down.
@menu
-* Summary Score Commands:: Adding score entries for the current group.
-* Group Score Commands:: General score commands.
-* Score Variables:: Customize your scoring. (My, what terminology).
-* Score File Format:: What a score file may contain.
-* Score File Editing:: You can edit score files by hand as well.
-* Adaptive Scoring:: Big Sister Gnus knows what you read.
-* Home Score File:: How to say where new score entries are to go.
-* Followups To Yourself:: Having Gnus notice when people answer you.
-* Scoring Tips:: How to score effectively.
-* Reverse Scoring:: That problem child of old is not problem.
-* Global Score Files:: Earth-spanning, ear-splitting score files.
-* Kill Files:: They are still here, but they can be ignored.
-* Converting Kill Files:: Translating kill files to score files.
-* GroupLens:: Getting predictions on what you like to read.
-* Advanced Scoring:: Using logical expressions to build score rules.
-* Score Decays:: It can be useful to let scores wither away.
+* Summary Score Commands:: Adding score entries for the current group.
+* Group Score Commands:: General score commands.
+* Score Variables:: Customize your scoring. (My, what terminology).
+* Score File Format:: What a score file may contain.
+* Score File Editing:: You can edit score files by hand as well.
+* Adaptive Scoring:: Big Sister Gnus knows what you read.
+* Home Score File:: How to say where new score entries are to go.
+* Followups To Yourself:: Having Gnus notice when people answer you.
+* Scoring On Other Headers:: Scoring on non-standard headers.
+* Scoring Tips:: How to score effectively.
+* Reverse Scoring:: That problem child of old is not problem.
+* Global Score Files:: Earth-spanning, ear-splitting score files.
+* Kill Files:: They are still here, but they can be ignored.
+* Converting Kill Files:: Translating kill files to score files.
+* GroupLens:: Getting predictions on what you like to read.
+* Advanced Scoring:: Using logical expressions to build score rules.
+* Score Decays:: It can be useful to let scores wither away.
@end menu
@item f
Score on followups---this matches the author name, and adds scores to
-the followups to this author.
+the followups to this author. (Using this key leads to the creation of
+@file{ADAPT} files.)
@item b
Score on the body.
Score on the head.
@item t
-Score on thread.
+Score on thread. (Using this key leads to the creation of @file{ADAPT}
+files.)
@end table
server.
@end table
-This variable can also be a list of functions. In that case, all these
-functions will be called with the group name as argument, and all the
-returned lists of score files will be applied. These functions can also
-return lists of score alists directly. In that case, the functions that
-return these non-file score alists should probably be placed before the
-``real'' score file functions, to ensure that the last score file
-returned is the local score file. Phu.
+This variable can also be a list of functions. In that case, all
+these functions will be called with the group name as argument, and
+all the returned lists of score files will be applied. These
+functions can also return lists of lists of score alists directly. In
+that case, the functions that return these non-file score alists
+should probably be placed before the ``real'' score file functions, to
+ensure that the last score file returned is the local score file.
+Phu.
For example, to do hierarchical scoring but use a non-server-specific
overall score file, you could use the value
@example
-(list (lambda (group) ("all.SCORE")) 'gnus-score-find-hierarchical)
+(list (lambda (group) ("all.SCORE"))
+ 'gnus-score-find-hierarchical)
@end example
@item gnus-score-expiry-days
(It's easy to get confused and think it's the other way around. But
it's not. I think.)
-When matching on @code{Lines}, be careful because some backends (like
+When matching on @code{Lines}, be careful because some back ends (like
@code{nndir}) do not generate @code{Lines} header, so every article ends
up being marked as having 0 lines. This can lead to strange results if
you happen to lower score of the articles with few lines.
is system-dependent.
+@node Scoring On Other Headers
+@section Scoring On Other Headers
+@cindex scoring on other headers
+
+Gnus is quite fast when scoring the ``traditional''
+headers---@samp{From}, @samp{Subject} and so on. However, scoring
+other headers requires writing a @code{head} scoring rule, which means
+that Gnus has to request every single article from the back end to find
+matches. This takes a long time in big groups.
+
+Now, there's not much you can do about this for news groups, but for
+mail groups, you have greater control. In the @pxref{To From
+Newsgroups} section of the manual, it's explained in greater detail what
+this mechanism does, but here's a cookbook example for @code{nnml} on
+how to allow scoring on the @samp{To} and @samp{Cc} headers.
+
+Put the following in your @file{.gnus.el} file.
+
+@lisp
+(setq gnus-extra-headers '(To Cc Newsgroups Keywords)
+ nnmail-extra-headers gnus-extra-headers)
+@end lisp
+
+Restart Gnus and rebuild your @code{nnml} overview files with the
+@kbd{M-x nnml-generate-nov-databases} command. This will take a long
+time if you have much mail.
+
+Now you can score on @samp{To} and @samp{Cc} as ``extra headers'' like
+so: @kbd{I e s p To RET <your name> RET}.
+
+See? Simple.
+
+
@node Scoring Tips
@section Scoring Tips
@cindex scoring tips
If you want to lower the score of articles that have been crossposted to
more than, say, 3 groups:
@lisp
-("xref" ("[^:\n]+:[0-9]+ +[^:\n]+:[0-9]+ +[^:\n]+:[0-9]+" -1000 nil r))
+("xref"
+ ("[^:\n]+:[0-9]+ +[^:\n]+:[0-9]+ +[^:\n]+:[0-9]+"
+ -1000 nil r))
@end lisp
@item Matching on the body
or each score file directory. Gnus will decide by itself what score
files are applicable to which group.
-Say you want to use the score file
+To use the score file
@file{/ftp@@ftp.gnus.org:/pub/larsi/ding/score/soc.motss.SCORE} and
-all score files in the @file{/ftp@@ftp.some-where:/pub/score} directory:
+all score files in the @file{/ftp@@ftp.some-where:/pub/score} directory,
+say this:
@lisp
(setq gnus-global-score-files
@end lisp
@findex gnus-score-search-global-directories
+@noindent
Simple, eh? Directory names must end with a @samp{/}. These
directories are typically scanned only once during each Gnus session.
If you feel the need to manually re-scan the remote directories, you can
@section GroupLens
@cindex GroupLens
-GroupLens is a collaborative filtering system that helps you work
-together with other people to find the quality news articles out of the
-huge volume of news articles generated every day.
+GroupLens (@uref{http://www.cs.umn.edu/Research/GroupLens/}) is a
+collaborative filtering system that helps you work together with other
+people to find the quality news articles out of the huge volume of
+news articles generated every day.
To accomplish this the GroupLens system combines your opinions about
articles you have already read with the opinions of others who have done
prediction to help you decide whether or not you want to read the
article.
+@sc{Note:} Unfortunately the GroupLens system seems to have shut down,
+so this section is mostly of historical interest.
+
@menu
-* Using GroupLens:: How to make Gnus use GroupLens.
-* Rating Articles:: Letting GroupLens know how you rate articles.
-* Displaying Predictions:: Displaying predictions given by GroupLens.
-* GroupLens Variables:: Customizing GroupLens.
+* Using GroupLens:: How to make Gnus use GroupLens.
+* Rating Articles:: Letting GroupLens know how you rate articles.
+* Displaying Predictions:: Displaying predictions given by GroupLens.
+* GroupLens Variables:: Customizing GroupLens.
@end menu
@item gnus-summary-grouplens-line-format
The summary line format used in GroupLens-enhanced summary buffers. It
accepts the same specs as the normal summary line format (@pxref{Summary
-Buffer Lines}). The default is @samp{%U%R%z%l%I%(%[%4L: %-20,20n%]%)
+Buffer Lines}). The default is @samp{%U%R%z%l%I%(%[%4L: %-23,23n%]%)
%s\n}.
@item grouplens-bbb-host
@node Advanced Scoring Examples
@subsection Advanced Scoring Examples
+Please note that the following examples are score file rules. To
+make a complete score file from them, surround them with another pair
+of parentheses.
+
Let's say you want to increase the score of articles written by Lars
when he's talking about Gnus:
Gnus will try to decay scores once a day. If you haven't run Gnus for
four days, Gnus will decay the scores four times, for instance.
+@iftex
+@iflatex
+@chapter Message
+@include message.texi
+@chapter Emacs MIME
+@include emacs-mime.texi
+@chapter Sieve
+@include sieve.texi
+@end iflatex
+@end iftex
@node Various
@chapter Various
@menu
-* Process/Prefix:: A convention used by many treatment commands.
-* Interactive:: Making Gnus ask you many questions.
-* Symbolic Prefixes:: How to supply some Gnus functions with options.
-* Formatting Variables:: You can specify what buffers should look like.
-* Windows Configuration:: Configuring the Gnus buffer windows.
-* Faces and Fonts:: How to change how faces look.
-* Compilation:: How to speed Gnus up.
-* Mode Lines:: Displaying information in the mode lines.
-* Highlighting and Menus:: Making buffers look all nice and cozy.
-* Buttons:: Get tendinitis in ten easy steps!
-* Daemons:: Gnus can do things behind your back.
-* NoCeM:: How to avoid spam and other fatty foods.
-* Undo:: Some actions can be undone.
-* Moderation:: What to do if you're a moderator.
-* XEmacs Enhancements:: There are more pictures and stuff under XEmacs.
-* Fuzzy Matching:: What's the big fuzz?
-* Thwarting Email Spam:: A how-to on avoiding unsolicited commercial email.
-* Various Various:: Things that are really various.
+* Process/Prefix:: A convention used by many treatment commands.
+* Interactive:: Making Gnus ask you many questions.
+* Symbolic Prefixes:: How to supply some Gnus functions with options.
+* Formatting Variables:: You can specify what buffers should look like.
+* Window Layout:: Configuring the Gnus buffer windows.
+* Faces and Fonts:: How to change how faces look.
+* Compilation:: How to speed Gnus up.
+* Mode Lines:: Displaying information in the mode lines.
+* Highlighting and Menus:: Making buffers look all nice and cozy.
+* Buttons:: Get tendinitis in ten easy steps!
+* Daemons:: Gnus can do things behind your back.
+* NoCeM:: How to avoid spam and other fatty foods.
+* Undo:: Some actions can be undone.
+* Moderation:: What to do if you're a moderator.
+* Image Enhancements:: Modern versions of Emacs/XEmacs can display images.
+* Fuzzy Matching:: What's the big fuzz?
+* Thwarting Email Spam:: A how-to on avoiding unsolicited commercial email.
+* Various Various:: Things that are really various.
@end menu
I'm not, so I've added a second prefix---the @dfn{symbolic prefix}. The
prefix key is @kbd{M-i} (@code{gnus-symbolic-argument}), and the next
character typed in is the value. You can stack as many @kbd{M-i}
-prefixes as you want. @kbd{M-i a M-C-u} means ``feed the @kbd{M-C-u}
-command the symbolic prefix @code{a}''. @kbd{M-i a M-i b M-C-u} means
-``feed the @kbd{M-C-u} command the symbolic prefixes @code{a} and
+prefixes as you want. @kbd{M-i a C-M-u} means ``feed the @kbd{C-M-u}
+command the symbolic prefix @code{a}''. @kbd{M-i a M-i b C-M-u} means
+``feed the @kbd{C-M-u} command the symbolic prefixes @code{a} and
@code{b}''. You get the drift.
Typing in symbolic prefixes to commands that don't accept them doesn't
lots of percentages everywhere.
@menu
-* Formatting Basics:: A formatting variable is basically a format string.
-* Mode Line Formatting:: Some rules about mode line formatting variables.
-* Advanced Formatting:: Modifying output in various ways.
-* User-Defined Specs:: Having Gnus call your own functions.
-* Formatting Fonts:: Making the formatting look colorful and nice.
+* Formatting Basics:: A formatting variable is basically a format string.
+* Mode Line Formatting:: Some rules about mode line formatting variables.
+* Advanced Formatting:: Modifying output in various ways.
+* User-Defined Specs:: Having Gnus call your own functions.
+* Formatting Fonts:: Making the formatting look colorful and nice.
+* Positioning Point:: Moving point to a position after an operation.
+* Tabulation:: Tabulating your output.
+* Wide Characters:: Dealing with wide characters.
@end menu
Currently Gnus uses the following formatting variables:
means that the field will never be more than 6 characters wide and never
less than 4 characters wide.
+Also Gnus supports some extended format specifications, such as
+@samp{%&user-date;}.
@node Mode Line Formatting
@subsection Mode Line Formatting
specifier. This function may also be called with dummy values, so it
should protect against that.
+Also Gnus supports extended user-defined specs, such as @samp{%u&foo;}.
+Gnus will call the function @code{gnus-user-format-function-}@samp{foo}.
+
You can also use tilde modifiers (@pxref{Advanced Formatting} to achieve
much the same without defining new functions. Here's an example:
@samp{%~(form (count-lines (point-min) (point)))@@}. The form
Note that the @samp{%(} specs (and friends) do not make any sense on the
mode-line variables.
+@node Positioning Point
+@subsection Positioning Point
+
+Gnus usually moves point to a pre-defined place on each line in most
+buffers. By default, point move to the first colon character on the
+line. You can customize this behaviour in three different ways.
+
+You can move the colon character to somewhere else on the line.
+
+@findex gnus-goto-colon
+You can redefine the function that moves the point to the colon. The
+function is called @code{gnus-goto-colon}.
+
+But perhaps the most convenient way to deal with this, if you don't want
+to have a colon in your line, is to use the @samp{%C} specifier. If you
+put a @samp{%C} somewhere in your format line definition, Gnus will
+place point there.
+
+
+@node Tabulation
+@subsection Tabulation
+
+You can usually line up your displays by padding and cutting your
+strings. However, when combining various strings of different size, it
+can often be more convenient to just output the strings, and then worry
+about lining up the following text afterwards.
+
+To do that, Gnus supplies tabulator specs--@samp{%=}. There are two
+different types---@dfn{hard tabulators} and @dfn{soft tabulators}.
+
+@samp{%50=} will insert space characters to pad the line up to column
+50. If the text is already past column 50, nothing will be inserted.
+This is the soft tabulator.
+
+@samp{%-50=} will insert space characters to pad the line up to column
+50. If the text is already past column 50, the excess text past column
+50 will be removed. This is the hard tabulator.
+
+
+@node Wide Characters
+@subsection Wide Characters
+
+Proportional fonts in most countries have characters of the same width.
+Some countries, however, use Latin characters mixed with wider
+characters---most notable East Asian countries.
+
+The problem is that when formatting, Gnus assumes that if a string is 10
+characters wide, it'll be 10 Latin characters wide on the screen. In
+these coutries, that's not true.
-@node Windows Configuration
-@section Windows Configuration
-@cindex windows configuration
+@vindex gnus-use-correct-string-widths
+To help fix this, you can set @code{gnus-use-correct-string-widths} to
+@code{t}. This makes buffer generation slower, but the results will be
+prettieer. The default value is @code{t}.
+
+
+
+@node Window Layout
+@section Window Layout
+@cindex window layout
No, there's nothing here about X, so be quiet.
may look like:
@example
-split = frame | horizontal | vertical | buffer | form
-frame = "(frame " size *split ")"
-horizontal = "(horizontal " size *split ")"
-vertical = "(vertical " size *split ")"
-buffer = "(" buffer-name " " size *[ "point" ] *[ "frame-focus"] ")"
-size = number | frame-params
-buffer-name = group | article | summary ...
+split = frame | horizontal | vertical | buffer | form
+frame = "(frame " size *split ")"
+horizontal = "(horizontal " size *split ")"
+vertical = "(vertical " size *split ")"
+buffer = "(" buf-name " " size *[ "point" ] *[ "frame-focus"] ")"
+size = number | frame-params
+buf-name = group | article | summary ...
@end example
The limitations are that the @code{frame} split can only appear as the
accomplish that, something like the following can be done:
@lisp
-(message (frame 1.0
- (if (not (buffer-live-p gnus-summary-buffer))
- (car (cdr (assoc 'group gnus-buffer-configuration)))
- (car (cdr (assoc 'summary gnus-buffer-configuration))))
- (vertical ((user-position . t) (top . 1) (left . 1)
- (name . "Message"))
- (message 1.0 point))))
+(message
+ (frame 1.0
+ (if (not (buffer-live-p gnus-summary-buffer))
+ (car (cdr (assoc 'group gnus-buffer-configuration)))
+ (car (cdr (assoc 'summary gnus-buffer-configuration))))
+ (vertical ((user-position . t) (top . 1) (left . 1)
+ (name . "Message"))
+ (message 1.0 point))))
@end lisp
@findex gnus-add-configuration
@subsection Example Window Configurations
@itemize @bullet
-@item
+@item
Narrow left hand side occupied by group buffer. Right hand side split
between summary buffer (top one-sixth) and article buffer (bottom).
@findex gnus-undo
The undoability is provided by the @code{gnus-undo-mode} minor mode. It
is used if @code{gnus-use-undo} is non-@code{nil}, which is the
-default. The @kbd{M-C-_} key performs the @code{gnus-undo}
+default. The @kbd{C-M-_} key performs the @code{gnus-undo}
command, which should feel kinda like the normal Emacs @code{undo}
command.
@end lisp
-@node XEmacs Enhancements
-@section XEmacs Enhancements
-@cindex XEmacs
+@node Image Enhancements
+@section Image Enhancements
-XEmacs is able to display pictures and stuff, so Gnus has taken
-advantage of that.
+XEmacs, as well as Emacs 21, is able to display pictures and stuff, so
+Gnus has taken advantage of that.
@menu
-* Picons:: How to display pictures of what your reading.
-* Smileys:: Show all those happy faces the way they were meant to be shown.
-* Toolbar:: Click'n'drool.
-* XVarious:: Other XEmacsy Gnusey variables.
+* Picons:: How to display pictures of what you're reading.
+* Smileys:: Show all those happy faces the way they were meant to be shown.
+* X-Face:: Display a funky, teensy black-and-white image.
+* Toolbar:: Click'n'drool.
+* XVarious:: Other XEmacsy Gnusey variables.
@end menu
over your shoulder as you read news.
@menu
-* Picon Basics:: What are picons and How do I get them.
-* Picon Requirements:: Don't go further if you aren't using XEmacs.
-* Easy Picons:: Displaying Picons---the easy way.
-* Hard Picons:: The way you should do it. You'll learn something.
-* Picon Useless Configuration:: Other variables you can trash/tweak/munge/play with.
+* Picon Basics:: What are picons and How do I get them.
+* Picon Requirements:: Don't go further if you aren't using XEmacs.
+* Easy Picons:: Displaying Picons---the easy way.
+* Hard Picons:: The way you should do it. You'll learn something.
+* Picon Useless Configuration:: Other variables you can trash/tweak/munge/play with.
@end menu
picons to be installed into a location pointed to by
@code{gnus-picons-database}.
+If you are using Debian GNU/Linux, saying @samp{apt-get install
+picons.*} will install the picons where Gnus can find them.
+
@node Picon Requirements
@subsubsection Picon Requirements
-To have Gnus display Picons for you, you must be running XEmacs
-19.13 or greater since all other versions of Emacs aren't yet able to
-display images.
-
-Additionally, you must have @code{x} support compiled into XEmacs. To
-display color picons which are much nicer than the black & white one,
-you also need one of @code{xpm} or @code{gif} compiled into XEmacs.
+To have Gnus display Picons for you, you must have @code{x} support
+compiled into XEmacs. To display color picons which are much nicer
+than the black & white one, you also need one of @code{xpm} or
+@code{gif} compiled into XEmacs.
@vindex gnus-picons-convert-x-face
If you want to display faces from @code{X-Face} headers, you should have
the @code{xface} support compiled into XEmacs. Otherwise you must have
the @code{netpbm} utilities installed, or munge the
@code{gnus-picons-convert-x-face} variable to use something else.
-
+(NOTE: @code{x-face} is used in the variable name, not @code{xface})
@node Easy Picons
@subsubsection Easy Picons
valid places could be @code{article}, @code{summary}, or
@samp{*scratch*} for all I care. Just make sure that you've made the
buffer visible using the standard Gnus window configuration
-routines---@pxref{Windows Configuration}.
+routines---@pxref{Window Layout}.
@item gnus-picons-group-excluded-groups
@vindex gnus-picons-group-excluded-groups
in the @code{gnus-picons-display-where} buffer.
@item gnus-picons-article-display-x-face
-@findex gnus-article-display-picons
+@findex gnus-picons-article-display-x-face
Decodes and displays the X-Face header if present.
+(NOTE: @code{x-face} is used in the function name, not @code{xface})
@end table
(@code{xbm}). Defaults to @code{(format "@{ echo '/* Width=48,
Height=48 */'; uncompface; @} | icontopbm | pbmtoxbm > %s"
gnus-picons-x-face-file-name)}
+(NOTE: @code{x-face} is used in the variable name, not @code{xface})
@item gnus-picons-x-face-file-name
@vindex gnus-picons-x-face-file-name
Names a temporary file to store the @code{X-Face} bitmap in. Defaults
to @code{(format "/tmp/picon-xface.%s.xbm" (user-login-name))}.
+(NOTE: @code{x-face} is used in the variable name, not @code{xface})
@item gnus-picons-has-modeline-p
@vindex gnus-picons-has-modeline-p
@iftex
@iflatex
-\gnusfig{-3cm}{0.5cm}{\epsfig{figure=tmp/BigFace.ps,height=20cm}}
+\gnusfig{-3cm}{0.5cm}{\epsfig{figure=ps/BigFace,height=20cm}}
\input{smiley}
@end iflatex
@end iftex
@end table
+@node X-Face
+@subsection X-Face
+@cindex x-face
+
+@code{X-Face} headers describe a 48x48 pixel black-and-white image
+that's supposed to represent the author of the message. It seems to
+be supported by an ever-growing number of mail and news readers.
+
+@cindex x-face
+@findex gnus-article-display-x-face
+@findex gnus-article-x-face-command
+@vindex gnus-article-x-face-command
+@vindex gnus-article-x-face-too-ugly
+@iftex
+@iflatex
+\include{xface}
+@end iflatex
+@end iftex
+@c @anchor{X-Face}
+
+Decoding an @code{X-Face} header either requires an Emacs that has
+@samp{compface} support (which most XEmacs versions has), or that you
+have @samp{compface} installed on your system. If either is true,
+Gnus will default to displaying @code{X-Face} headers.
+
+The variable that controls this is the
+@code{gnus-article-x-face-command} variable. If this variable is a
+string, this string will be executed in a sub-shell. If it is a
+function, this function will be called with the face as the argument.
+If the @code{gnus-article-x-face-too-ugly} (which is a regexp) matches
+the @code{From} header, the face will not be shown.
+
+The default action under Emacs 20 is to fork off the @code{display}
+program@footnote{@code{display} is from the ImageMagick package. For
+the @code{uncompface} and @code{icontopbm} programs look for a package
+like @code{compface} or @code{faces-xface} on a GNU/Linux system.} to
+view the face.
+
+Under XEmacs or Emacs 21+ with suitable image support, the default
+action is to display the face before the @code{From} header. (It's
+nicer if XEmacs has been compiled with @code{X-Face} support---that
+will make display somewhat faster. If there's no native @code{X-Face}
+support, Gnus will try to convert the @code{X-Face} header using
+external programs from the @code{pbmplus} package and
+friends.@footnote{On a GNU/Linux system look for packages with names
+like @code{netpbm}, @code{libgr-progs} and @code{compface}.})
+
+(NOTE: @code{x-face} is used in the variable/function names, not
+@code{xface}).
+
+
@node Toolbar
@subsection Toolbar
@item gnus-verbose-backends
@vindex gnus-verbose-backends
This variable works the same way as @code{gnus-verbose}, but it applies
-to the Gnus backends instead of Gnus proper.
+to the Gnus back ends instead of Gnus proper.
@item nnheader-max-head-length
@vindex nnheader-max-head-length
-When the backends read straight heads of articles, they all try to read
+When the back ends read straight heads of articles, they all try to read
as little as possible. This variable (default 4096) specifies
-the absolute max length the backends will try to read before giving up
+the absolute max length the back ends will try to read before giving up
on finding a separator line between the head and the body. If this
variable is @code{nil}, there is no upper read bound. If it is
-@code{t}, the backends won't try to read the articles piece by piece,
+@code{t}, the back ends won't try to read the articles piece by piece,
but read the entire articles. This makes sense with some versions of
@code{ange-ftp} or @code{efs}.
@end table
-
@node The End
@chapter The End
@chapter Appendices
@menu
-* History:: How Gnus got where it is today.
-* On Writing Manuals:: Why this is not a beginner's guide.
-* Terminology:: We use really difficult, like, words here.
-* Customization:: Tailoring Gnus to your needs.
-* Troubleshooting:: What you might try if things do not work.
-* Gnus Reference Guide:: Rilly, rilly technical stuff.
-* Emacs for Heathens:: A short introduction to Emacsian terms.
-* Frequently Asked Questions:: A question-and-answer session.
+* XEmacs:: Requirements for installing under XEmacs.
+* History:: How Gnus got where it is today.
+* On Writing Manuals:: Why this is not a beginner's guide.
+* Terminology:: We use really difficult, like, words here.
+* Customization:: Tailoring Gnus to your needs.
+* Troubleshooting:: What you might try if things do not work.
+* Gnus Reference Guide:: Rilly, rilly technical stuff.
+* Emacs for Heathens:: A short introduction to Emacsian terms.
+* Frequently Asked Questions::
@end menu
+@node XEmacs
+@section XEmacs
+@cindex XEmacs
+@cindex Installing under XEmacs
+
+XEmacs is distributed as a collection of packages. You should install
+whatever packages the Gnus XEmacs package requires. The current
+requirements are @samp{gnus}, @samp{w3}, @samp{mh-e},
+@samp{mailcrypt}, @samp{rmail}, @samp{eterm}, @samp{mail-lib},
+@samp{xemacs-base}, and @samp{fsf-compat}.
+
+
@node History
@section History
``@sc{gnus}''. New vs. old.
@menu
-* Gnus Versions:: What Gnus versions have been released.
-* Other Gnus Versions:: Other Gnus versions that also have been released.
-* Why?:: What's the point of Gnus?
-* Compatibility:: Just how compatible is Gnus with @sc{gnus}?
-* Conformity:: Gnus tries to conform to all standards.
-* Emacsen:: Gnus can be run on a few modern Emacsen.
-* Gnus Development:: How Gnus is developed.
-* Contributors:: Oodles of people.
-* New Features:: Pointers to some of the new stuff in Gnus.
+* Gnus Versions:: What Gnus versions have been released.
+* Other Gnus Versions:: Other Gnus versions that also have been released.
+* Why?:: What's the point of Gnus?
+* Compatibility:: Just how compatible is Gnus with @sc{gnus}?
+* Conformity:: Gnus tries to conform to all standards.
+* Emacsen:: Gnus can be run on a few modern Emacsen.
+* Gnus Development:: How Gnus is developed.
+* Contributors:: Oodles of people.
+* New Features:: Pointers to some of the new stuff in Gnus.
@end menu
Gnus offers no real solutions to these questions, but I would very much
like to see Gnus being used as a testing ground for new methods of
reading and fetching news. Expanding on @sc{Umeda}-san's wise decision
-to separate the newsreader from the backends, Gnus now offers a simple
-interface for anybody who wants to write new backends for fetching mail
+to separate the newsreader from the back ends, Gnus now offers a simple
+interface for anybody who wants to write new back ends for fetching mail
and news from different sources. I have added hooks for customizations
everywhere I could imagine it being useful. By doing so, I'm inviting
every one of you to explore and invent.
Gnus is developed in a two-phased cycle. The first phase involves much
discussion on the @samp{ding@@gnus.org} mailing list, where people
-propose changes and new features, post patches and new backends. This
+propose changes and new features, post patches and new back ends. This
phase is called the @dfn{alpha} phase, since the Gnusae released in this
phase are @dfn{alpha releases}, or (perhaps more commonly in other
circles) @dfn{snapshots}. During this phase, Gnus is assumed to be
Luis Fernandes---design and graphics.
@item
+Joe Reiss---creator of the smiley faces.
+
+@item
Justin Sheehy--the FAQ maintainer.
@item
@cindex new features
@menu
-* ding Gnus:: New things in Gnus 5.0/5.1, the first new Gnus.
-* September Gnus:: The Thing Formally Known As Gnus 5.2/5.3.
-* Red Gnus:: Third time best---Gnus 5.4/5.5.
-* Quassia Gnus:: Two times two is four, or Gnus 5.6/5.7.
-* Pterodactyl Gnus:: Pentad also starts with P, AKA Gnus 5.8/5.9.
+* ding Gnus:: New things in Gnus 5.0/5.1, the first new Gnus.
+* September Gnus:: The Thing Formally Known As Gnus 5.2/5.3.
+* Red Gnus:: Third time best---Gnus 5.4/5.5.
+* Quassia Gnus:: Two times two is four, or Gnus 5.6/5.7.
+* Pterodactyl Gnus:: Pentad also starts with P, AKA Gnus 5.8/5.9.
@end menu
These lists are, of course, just @emph{short} overviews of the
@item
You can read a number of different mail formats (@pxref{Getting Mail}).
-All the mail backends implement a convenient mail expiry scheme
+All the mail back ends implement a convenient mail expiry scheme
(@pxref{Expiring Mail}).
@item
@item
You can do lots of strange stuff with the Gnus window & frame
-configuration (@pxref{Windows Configuration}).
+configuration (@pxref{Window Layout}).
@item
You can click on buttons instead of using the keyboard
@iftex
@iflatex
-\gnusfig{-28cm}{0cm}{\epsfig{figure=tmp/september.ps,height=20cm}}
+\gnusfig{-28cm}{0cm}{\epsfig{figure=ps/september,height=20cm}}
@end iflatex
@end iftex
else (@pxref{Document Groups}).
@item
-Gnus has a new backend (@code{nnsoup}) to create/read SOUP packets
+Gnus has a new back end (@code{nnsoup}) to create/read SOUP packets
(@pxref{SOUP}).
@item
Article headers can be buttonized (@pxref{Article Washing}).
@item
-All mail backends support fetching articles by @code{Message-ID}.
+All mail back ends support fetching articles by @code{Message-ID}.
@item
Duplicate mail can now be treated properly (@pxref{Duplicates}).
buffer (@pxref{Article Keymap}).
@item
-Frames can be part of @code{gnus-buffer-configuration} (@pxref{Windows
-Configuration}).
+Frames can be part of @code{gnus-buffer-configuration} (@pxref{Window
+Layout}).
@item
Mail can be re-scanned by a daemonic process (@pxref{Daemons}).
@iftex
@iflatex
-\marginpar[\mbox{}\hfill\epsfig{figure=tmp/fseptember.ps,height=5cm}]{\epsfig{figure=tmp/fseptember.ps,height=5cm}}
+\marginpar[\mbox{}\hfill\epsfig{figure=ps/fseptember,height=5cm}]{\epsfig{figure=ps/fseptember,height=5cm}}
@end iflatex
@end iftex
@iftex
@iflatex
-\gnusfig{-5.5cm}{-4cm}{\epsfig{figure=tmp/red.ps,height=20cm}}
+\gnusfig{-5.5cm}{-4cm}{\epsfig{figure=ps/red,height=20cm}}
@end iflatex
@end iftex
when generating lines in buffers (@pxref{Advanced Formatting}).
@item
-Several commands in the group buffer can be undone with @kbd{M-C-_}
+Several commands in the group buffer can be undone with @kbd{C-M-_}
(@pxref{Undo}).
@item
@item
A new command for reading collections of documents
-(@code{nndoc} with @code{nnvirtual} on top) has been added---@kbd{M-C-d}
+(@code{nndoc} with @code{nnvirtual} on top) has been added---@kbd{C-M-d}
(@pxref{Really Various Summary Commands}).
@item
Marks}).
@item
-A new mail-to-news backend makes it possible to post even when the @sc{nntp}
+A new mail-to-news back end makes it possible to post even when the @sc{nntp}
server doesn't allow posting (@pxref{Mail-To-News Gateways}).
@item
-A new backend for reading searches from Web search engines
+A new back end for reading searches from Web search engines
(@dfn{DejaNews}, @dfn{Alta Vista}, @dfn{InReference}) has been added
(@pxref{Web Searches}).
Commands}).
@iftex
@iflatex
-\marginpar[\mbox{}\hfill\epsfig{figure=tmp/fred.ps,width=3cm}]{\epsfig{figure=tmp/fred.ps,width=3cm}}
+\marginpar[\mbox{}\hfill\epsfig{figure=ps/fred,width=3cm}]{\epsfig{figure=ps/fred,width=3cm}}
@end iflatex
@end iftex
@pxref{Gnus Unplugged} for the full story.
@item
- The @code{nndraft} backend has returned, but works differently than
+ The @code{nndraft} back end has returned, but works differently than
before. All Message buffers are now also articles in the @code{nndraft}
group, which is created automatically.
updated by the @code{gnus-start-date-timer} command.
@item
- Web listserv archives can be read with the @code{nnlistserv} backend.
+ Web listserv archives can be read with the @code{nnlistserv} back end.
@item
Old dejanews archives can now be read by @code{nnweb}.
@itemize @bullet
-@item The mail-fetching functions have changed. See the manual for the
+@item
+The mail-fetching functions have changed. See the manual for the
many details. In particular, all procmail fetching variables are gone.
If you used procmail like in
(setq nnmail-procmail-suffix "\\.in")
@end lisp
-this now has changed to
+this now has changed to
@lisp
(setq mail-sources
More information is available in the info doc at Select Methods ->
Getting Mail -> Mail Sources
-@item Gnus is now a MIME-capable reader. This affects many parts of
+@item
+Gnus is now a MIME-capable reader. This affects many parts of
Gnus, and adds a slew of new commands. See the manual for details.
-@item Gnus has also been multilingualized. This also affects too
+@item
+Gnus has also been multilingualized. This also affects too
many parts of Gnus to summarize here, and adds many new variables.
-@item @code{gnus-auto-select-first} can now be a function to be
+@item
+@code{gnus-auto-select-first} can now be a function to be
called to position point.
-@item The user can now decide which extra headers should be included in
+@item
+The user can now decide which extra headers should be included in
summary buffers and NOV files.
-@item @code{gnus-article-display-hook} has been removed. Instead, a number
+@item
+@code{gnus-article-display-hook} has been removed. Instead, a number
of variables starting with @code{gnus-treat-} have been added.
-@item The Gnus posting styles have been redone again and now works in a
+@item
+The Gnus posting styles have been redone again and now works in a
subtly different manner.
-@item New web-based backends have been added: @code{nnslashdot},
+@item
+New web-based back ends have been added: @code{nnslashdot},
@code{nnwarchive} and @code{nnultimate}. nnweb has been revamped,
again, to keep up with ever-changing layouts.
-@item Gnus can now read IMAP mail via @code{nnimap}.
+@item
+Gnus can now read IMAP mail via @code{nnimap}.
@end itemize
that's already there. This is not how this manual is written. When
implementing something, I write the manual entry for that something
straight away. I then see that it's difficult to explain the
-functionality, so I write how it's supposed to be, and then I change the
+functionality, so I write how it's supposed to be, and then I change the
implementation. Writing the documentation and writing the code goes
hand in hand.
This, of course, means that this manual has no, or little, flow. It
documents absolutely everything in Gnus, but often not where you're
-looking for it. It is a reference manual, and not a guide to how to get
+looking for it. It is a reference manual, and not a guide to how to get
started with Gnus.
-That would be a totally different book, that should be written using the
+That would be a totally different book, that should be written using the
reference manual as source material. It would look quite differently.
Post an article to the current newsgroup responding to the article you
are reading.
-@item backend
-@cindex backend
-Gnus gets fed articles from a number of backends, both news and mail
-backends. Gnus does not handle the underlying media, so to speak---this
-is all done by the backends.
+@item back end
+@cindex back end
+Gnus gets fed articles from a number of back ends, both news and mail
+back ends. Gnus does not handle the underlying media, so to speak---this
+is all done by the back ends.
@item native
@cindex native
-Gnus will always use one method (and backend) as the @dfn{native}, or
+Gnus will always use one method (and back end) as the @dfn{native}, or
default, way of getting news.
@item foreign
@cindex foreign
You can also have any number of foreign groups active at the same time.
-These are groups that use non-native non-secondary backends for getting
+These are groups that use non-native non-secondary back ends for getting
news.
@item secondary
@cindex secondary
-Secondary backends are somewhere half-way between being native and being
+Secondary back ends are somewhere half-way between being native and being
foreign, but they mostly act like they are native.
@item article
@item @sc{nov}
@cindex nov
-When Gnus enters a group, it asks the backend for the headers of all
+When Gnus enters a group, it asks the back end for the headers of all
unread articles in the group. Most servers support the News OverView
format, which is more compact and much faster to read and parse than the
normal @sc{head} format.
@item select method
@cindex select method
-A structure that specifies the backend, the server and the virtual
+A structure that specifies the back end, the server and the virtual
server settings.
@item virtual server
for some quite common situations.
@menu
-* Slow/Expensive Connection:: You run a local Emacs and get the news elsewhere.
-* Slow Terminal Connection:: You run a remote Emacs.
-* Little Disk Space:: You feel that having large setup files is icky.
-* Slow Machine:: You feel like buying a faster machine.
+* Slow/Expensive Connection:: You run a local Emacs and get the news elsewhere.
+* Slow Terminal Connection:: You run a remote Emacs.
+* Little Disk Space:: You feel that having large setup files is icky.
+* Slow Machine:: You feel like buying a faster machine.
@end menu
it somewhere it can be reached, and include the URL of the picture in
the bug report.
+@cindex patches
+If you would like to contribute a patch to fix bugs or make
+improvements, please produce the patch using @samp{diff -u}.
+
If you just need help, you are better off asking on
@samp{gnu.emacs.gnus}. I'm not very helpful.
You can never expect the internals of a program not to change, but I
will be defining (in some details) the interface between Gnus and its
-backends (this is written in stone), the format of the score files
+back ends (this is written in stone), the format of the score files
(ditto), data structures (some are less likely to change than others)
and general methods of operation.
@menu
-* Gnus Utility Functions:: Common functions and variable to use.
-* Backend Interface:: How Gnus communicates with the servers.
-* Score File Syntax:: A BNF definition of the score file standard.
-* Headers:: How Gnus stores headers internally.
-* Ranges:: A handy format for storing mucho numbers.
-* Group Info:: The group info format.
-* Extended Interactive:: Symbolic prefixes and stuff.
-* Emacs/XEmacs Code:: Gnus can be run under all modern Emacsen.
-* Various File Formats:: Formats of files that Gnus use.
+* Gnus Utility Functions:: Common functions and variable to use.
+* Back End Interface:: How Gnus communicates with the servers.
+* Score File Syntax:: A BNF definition of the score file standard.
+* Headers:: How Gnus stores headers internally.
+* Ranges:: A handy format for storing mucho numbers.
+* Group Info:: The group info format.
+* Extended Interactive:: Symbolic prefixes and stuff.
+* Emacs/XEmacs Code:: Gnus can be run under all modern Emacsen.
+* Various File Formats:: Formats of files that Gnus use.
@end menu
@item gnus-news-group-p
@findex gnus-news-group-p
-Says whether @var{group} came from a news backend.
+Says whether @var{group} came from a news back end.
@item gnus-ephemeral-group-p
@findex gnus-ephemeral-group-p
@item gnus-check-backend-function
@findex gnus-check-backend-function
-Takes two parameters, @var{function} and @var{group}. If the backend
+Takes two parameters, @var{function} and @var{group}. If the back end
@var{group} comes from supports @var{function}, return non-@code{nil}.
@lisp
@end table
-@node Backend Interface
-@subsection Backend Interface
+@node Back End Interface
+@subsection Back End Interface
Gnus doesn't know anything about @sc{nntp}, spools, mail or virtual
groups. It only knows how to talk to @dfn{virtual servers}. A virtual
-server is a @dfn{backend} and some @dfn{backend variables}. As examples
+server is a @dfn{back end} and some @dfn{back end variables}. As examples
of the first, we have @code{nntp}, @code{nnspool} and @code{nnmbox}. As
examples of the latter we have @code{nntp-port-number} and
@code{nnmbox-directory}.
-When Gnus asks for information from a backend---say @code{nntp}---on
+When Gnus asks for information from a back end---say @code{nntp}---on
something, it will normally include a virtual server name in the
-function parameters. (If not, the backend should use the ``current''
+function parameters. (If not, the back end should use the ``current''
virtual server.) For instance, @code{nntp-request-list} takes a virtual
server as its only (optional) parameter. If this virtual server hasn't
been opened, the function should fail.
Here the virtual server name is @samp{odd-one} while the name of
the physical server is @samp{ifi.uio.no}.
-The backends should be able to switch between several virtual servers.
-The standard backends implement this by keeping an alist of virtual
+The back ends should be able to switch between several virtual servers.
+The standard back ends implement this by keeping an alist of virtual
server environments that they pull down/push up when needed.
There are two groups of interface functions: @dfn{required functions},
the function call. Functions that fail should return @code{nil} as the
return value.
-Some backends could be said to be @dfn{server-forming} backends, and
-some might be said not to be. The latter are backends that generally
+Some back ends could be said to be @dfn{server-forming} back ends, and
+some might be said not to be. The latter are back ends that generally
only operate on one group at a time, and have no concept of ``server''
-- they have a group, and they deliver info on that group and nothing
more.
-In the examples and definitions I will refer to the imaginary backend
+Gnus identifies each message by way of group name and article number. A
+few remarks about these article numbers might be useful. First of all,
+the numbers are positive integers. Secondly, it is normally not
+possible for later articles to `re-use' older article numbers without
+confusing Gnus. That is, if a group has ever contained a message
+numbered 42, then no other message may get that number, or Gnus will get
+mightily confused.@footnote{See the function
+@code{nnchoke-request-update-info}, @ref{Optional Back End Functions}.}
+Third, article numbers must be assigned in order of arrival in the
+group; this is not necessarily the same as the date of the message.
+
+The previous paragraph already mentions all the `hard' restrictions that
+article numbers must fulfill. But it seems that it might be useful to
+assign @emph{consecutive} article numbers, for Gnus gets quite confused
+if there are holes in the article numbering sequence. However, due to
+the `no-reuse' restriction, holes cannot be avoided altogether. It's
+also useful for the article numbers to start at 1 to avoid running out
+of numbers as long as possible.
+
+In the examples and definitions I will refer to the imaginary back end
@code{nnchoke}.
@cindex @code{nnchoke}
@menu
-* Required Backend Functions:: Functions that must be implemented.
-* Optional Backend Functions:: Functions that need not be implemented.
-* Error Messaging:: How to get messages and report errors.
-* Writing New Backends:: Extending old backends.
-* Hooking New Backends Into Gnus:: What has to be done on the Gnus end.
-* Mail-like Backends:: Some tips on mail backends.
+* Required Back End Functions:: Functions that must be implemented.
+* Optional Back End Functions:: Functions that need not be implemented.
+* Error Messaging:: How to get messages and report errors.
+* Writing New Back Ends:: Extending old back ends.
+* Hooking New Back Ends Into Gnus:: What has to be done on the Gnus end.
+* Mail-like Back Ends:: Some tips on mail back ends.
@end menu
-@node Required Backend Functions
-@subsubsection Required Backend Functions
+@node Required Back End Functions
+@subsubsection Required Back End Functions
@table @code
@item (nnchoke-retrieve-headers ARTICLES &optional GROUP SERVER FETCH-OLD)
@var{articles} is either a range of article numbers or a list of
-@code{Message-ID}s. Current backends do not fully support either---only
-sequences (lists) of article numbers, and most backends do not support
+@code{Message-ID}s. Current back ends do not fully support either---only
+sequences (lists) of article numbers, and most back ends do not support
retrieval of @code{Message-ID}s. But they should try for both.
The result data should either be HEADs or NOV lines, and the result
headers", in some meaning of the word. This is generally done by
fetching (at most) @var{fetch-old} extra headers less than the smallest
article number in @code{articles}, and filling the gaps as well. The
-presence of this parameter can be ignored if the backend finds it
+presence of this parameter can be ignored if the back end finds it
cumbersome to follow the request. If this is non-@code{nil} and not a
number, do maximum fetches.
@var{server} is here the virtual server name. @var{definitions} is a
list of @code{(VARIABLE VALUE)} pairs that define this virtual server.
-If the server can't be opened, no error should be signaled. The backend
+If the server can't be opened, no error should be signaled. The back end
may then choose to refuse further attempts at connecting to this
server. In fact, it should do so.
@item (nnchoke-request-close)
-Close connection to all servers and free all resources that the backend
-have reserved. All buffers that have been created by that backend
+Close connection to all servers and free all resources that the back end
+have reserved. All buffers that have been created by that back end
should be killed. (Not the @code{nntp-server-buffer}, though.) This
function is generally only called when Gnus is shutting down.
@item (nnchoke-close-group GROUP &optional SERVER)
Close @var{group} and free any resources connected to it. This will be
-a no-op on most backends.
+a no-op on most back ends.
There should be no data returned.
@end table
-@node Optional Backend Functions
-@subsubsection Optional Backend Functions
+@node Optional Back End Functions
+@subsubsection Optional Back End Functions
@table @code
@item (nnchoke-request-update-info GROUP INFO &optional SERVER)
-A Gnus group info (@pxref{Group Info}) is handed to the backend for
-alterations. This comes in handy if the backend really carries all the
+A Gnus group info (@pxref{Group Info}) is handed to the back end for
+alterations. This comes in handy if the back end really carries all the
information (as is the case with virtual and imap groups). This
function should destructively alter the info to suit its needs, and
should return the (altered) group info.
Set/remove/add marks on articles. Normally Gnus handles the article
marks (such as read, ticked, expired etc) internally, and store them in
-@code{~/.newsrc.eld}. Some backends (such as @sc{imap}) however carry
+@code{~/.newsrc.eld}. Some back ends (such as @sc{imap}) however carry
all information about the articles on the server, so Gnus need to
propagate the mark information to the server.
@end example
RANGE is a range of articles you wish to update marks on. ACTION is
-@code{set}, @code{add} or @code{del}, respectively used for removing all
-existing marks and setting them as specified, adding (preserving the
-marks not mentioned) mark and removing (preserving the marks not
-mentioned) marks. MARK is a list of marks; where each mark is a symbol.
-Currently used marks are @code{read}, @code{tick}, @code{reply},
-@code{expire}, @code{killed}, @code{dormant}, @code{save},
-@code{download} and @code{unsend}, but your backend should, if possible,
-not limit itself to these.
+@code{add} or @code{del}, used to add marks or remove marks
+(preserving all marks not mentioned). MARK is a list of marks; where
+each mark is a symbol. Currently used marks are @code{read},
+@code{tick}, @code{reply}, @code{expire}, @code{killed},
+@code{dormant}, @code{save}, @code{download}, @code{unsend},
+@code{forward} and @code{recent}, but your back end should, if
+possible, not limit itself to these.
Given contradictory actions, the last action in the list should be the
effective one. That is, if your action contains a request to add the
@item (nnchoke-request-update-mark GROUP ARTICLE MARK)
-If the user tries to set a mark that the backend doesn't like, this
+If the user tries to set a mark that the back end doesn't like, this
function may change the mark. Gnus will use whatever this function
returns as the mark for @var{article} instead of the original
-@var{mark}. If the backend doesn't care, it must return the original
+@var{mark}. If the back end doesn't care, it must return the original
@var{mark}, and not @code{nil} or any other type of garbage.
The only use for this I can see is what @code{nnvirtual} does with
@item (nnchoke-request-scan &optional GROUP SERVER)
This function may be called at any time (by Gnus or anything else) to
-request that the backend check for incoming articles, in one way or
-another. A mail backend will typically read the spool file or query the
+request that the back end check for incoming articles, in one way or
+another. A mail back end will typically read the spool file or query the
POP server when this function is invoked. The @var{group} doesn't have
-to be heeded---if the backend decides that it is too much work just
+to be heeded---if the back end decides that it is too much work just
scanning for a single group, it may do a total scan of all groups. It
would be nice, however, to keep things local if that's practical.
@item (nnchoke-request-newgroups DATE &optional SERVER)
The result data from this function should be all groups that were
-created after @samp{date}, which is in normal human-readable date
-format. The data should be in the active buffer format.
+created after @samp{date}, which is in normal human-readable date format
+(i.e., the date format used in mail and news headers, and returned by
+the function @code{message-make-date} by default). The data should be
+in the active buffer format.
+
+It is okay for this function to return `too many' groups; some back ends
+might find it cheaper to return the full list of groups, rather than
+just the new groups. But don't do this for back ends with many groups.
+Normally, if the user creates the groups herself, there won't be too
+many groups, so nnml and the like are probably safe. But for back ends
+like nntp, where the groups have been created by the server, it is quite
+likely that there can be many groups.
@item (nnchoke-request-create-group GROUP &optional SERVER)
This function should run the expiry process on all articles in the
@var{articles} range (which is currently a simple list of article
-numbers.) It is left up to the backend to decide how old articles
+numbers.) It is left up to the back end to decide how old articles
should be before they are removed by this function. If @var{force} is
non-@code{nil}, all @var{articles} should be deleted, no matter how new
they are.
@findex nnheader-report
@findex nnheader-get-report
-The backends should use the function @code{nnheader-report} to report
+The back ends should use the function @code{nnheader-report} to report
error conditions---they should not raise errors when they aren't able to
-perform a request. The first argument to this function is the backend
+perform a request. The first argument to this function is the back end
symbol, and the rest are interpreted as arguments to @code{format} if
there are multiple of them, or just a string if there is one of them.
This function must always returns @code{nil}.
Gnus, in turn, will call @code{nnheader-get-report} when it gets a
@code{nil} back from a server, and this function returns the most
-recently reported message for the backend in question. This function
+recently reported message for the back end in question. This function
takes one argument---the server symbol.
-Internally, these functions access @var{backend}@code{-status-string},
-so the @code{nnchoke} backend will have its error message stored in
+Internally, these functions access @var{back-end}@code{-status-string},
+so the @code{nnchoke} back end will have its error message stored in
@code{nnchoke-status-string}.
-@node Writing New Backends
-@subsubsection Writing New Backends
+@node Writing New Back Ends
+@subsubsection Writing New Back Ends
-Many backends are quite similar. @code{nnml} is just like
+Many back ends are quite similar. @code{nnml} is just like
@code{nnspool}, but it allows you to edit the articles on the server.
@code{nnmh} is just like @code{nnml}, but it doesn't use an active file,
and it doesn't maintain overview databases. @code{nndir} is just like
editing articles.
It would make sense if it were possible to ``inherit'' functions from
-backends when writing new backends. And, indeed, you can do that if you
+back ends when writing new back ends. And, indeed, you can do that if you
want to. (You don't have to if you don't want to, of course.)
-All the backends declare their public variables and functions by using a
+All the back ends declare their public variables and functions by using a
package called @code{nnoo}.
-To inherit functions from other backends (and allow other backends to
-inherit functions from the current backend), you should use the
+To inherit functions from other back ends (and allow other back ends to
+inherit functions from the current back end), you should use the
following macros:
@table @code
declared with @code{defvoo} instead of @code{defvar}.
In addition to the normal @code{defvar} parameters, it takes a list of
-variables in the parent backends to map the variable to when executing
-a function in those backends.
+variables in the parent back ends to map the variable to when executing
+a function in those back ends.
@lisp
(defvoo nndir-directory nil
of @code{nndir}. (The same with @code{nnmh}.)
@item nnoo-define-basics
-This macro defines some common functions that almost all backends should
+This macro defines some common functions that almost all back ends should
have.
@example
@item deffoo
This macro is just like @code{defun} and takes the same parameters. In
addition to doing the normal @code{defun} things, it registers the
-function as being public so that other backends can inherit it.
+function as being public so that other back ends can inherit it.
@item nnoo-map-functions
-This macro allows mapping of functions from the current backend to
-functions from the parent backends.
+This macro allows mapping of functions from the current back end to
+functions from the parent back ends.
@example
(nnoo-map-functions nndir
value of @code{nndir-current-group}.
@item nnoo-import
-This macro allows importing functions from backends. It should be the
+This macro allows importing functions from back ends. It should be the
last thing in the source file, since it will only define functions that
haven't already been defined.
@end table
-Below is a slightly shortened version of the @code{nndir} backend.
+Below is a slightly shortened version of the @code{nndir} back end.
@lisp
;;; nndir.el --- single directory newsgroup access for Gnus
"*Non-nil means that nndir will never retrieve NOV headers."
nnml-nov-is-evil)
-(defvoo nndir-current-group "" nil nnml-current-group nnmh-current-group)
+(defvoo nndir-current-group ""
+ nil
+ nnml-current-group nnmh-current-group)
(defvoo nndir-top-directory nil nil nnml-directory nnmh-directory)
(defvoo nndir-get-new-mail nil nil nnml-get-new-mail nnmh-get-new-mail)
(unless (assq 'nndir-directory defs)
(push `(nndir-directory ,server) defs))
(push `(nndir-current-group
- ,(file-name-nondirectory (directory-file-name nndir-directory)))
+ ,(file-name-nondirectory
+ (directory-file-name nndir-directory)))
defs)
(push `(nndir-top-directory
,(file-name-directory (directory-file-name nndir-directory)))
@end lisp
-@node Hooking New Backends Into Gnus
-@subsubsection Hooking New Backends Into Gnus
+@node Hooking New Back Ends Into Gnus
+@subsubsection Hooking New Back Ends Into Gnus
@vindex gnus-valid-select-methods
-Having Gnus start using your new backend is rather easy---you just
+@findex gnus-declare-backend
+Having Gnus start using your new back end is rather easy---you just
declare it with the @code{gnus-declare-backend} functions. This will
-enter the backend into the @code{gnus-valid-select-methods} variable.
+enter the back end into the @code{gnus-valid-select-methods} variable.
-@code{gnus-declare-backend} takes two parameters---the backend name and
+@code{gnus-declare-backend} takes two parameters---the back end name and
an arbitrary number of @dfn{abilities}.
Here's an example:
(gnus-declare-backend "nnchoke" 'mail 'respool 'address)
@end lisp
+The above line would then go in the @file{nnchoke.el} file.
+
The abilities can be:
@table @code
@item mail
-This is a mailish backend---followups should (probably) go via mail.
+This is a mailish back end---followups should (probably) go via mail.
@item post
-This is a newsish backend---followups should (probably) go via news.
+This is a newsish back end---followups should (probably) go via news.
@item post-mail
-This backend supports both mail and news.
+This back end supports both mail and news.
@item none
-This is neither a post nor mail backend---it's something completely
+This is neither a post nor mail back end---it's something completely
different.
@item respool
It supports respooling---or rather, it is able to modify its source
articles and groups.
@item address
The name of the server should be in the virtual server name. This is
-true for almost all backends.
+true for almost all back ends.
@item prompt-address
The user should be prompted for an address when doing commands like
-@kbd{B} in the group buffer. This is true for backends like
+@kbd{B} in the group buffer. This is true for back ends like
@code{nntp}, but not @code{nnmbox}, for instance.
@end table
-@node Mail-like Backends
-@subsubsection Mail-like Backends
+@node Mail-like Back Ends
+@subsubsection Mail-like Back Ends
-One of the things that separate the mail backends from the rest of the
-backends is the heavy dependence by the mail backends on common
+One of the things that separate the mail back ends from the rest of the
+back ends is the heavy dependence by the mail back ends on common
functions in @file{nnmail.el}. For instance, here's the definition of
@code{nnml-request-scan}:
@table @var
@item method
-This should be a symbol to designate which backend is responsible for
+This should be a symbol to designate which back end is responsible for
the call.
@item exit-function
performed for one group only.
@end table
-@code{nnmail-get-new-mail} will call @var{backend}@code{-save-mail} to
-save each article. @var{backend}@code{-active-number} will be called to
+@code{nnmail-get-new-mail} will call @var{back-end}@code{-save-mail} to
+save each article. @var{back-end}@code{-active-number} will be called to
find the article number assigned to this article.
The function also uses the following variables:
-@var{backend}@code{-get-new-mail} (to see whether to get new mail for
-this backend); and @var{backend}@code{-group-alist} and
-@var{backend}@code{-active-file} to generate the new active file.
-@var{backend}@code{-group-alist} should be a group-active alist, like
+@var{back-end}@code{-get-new-mail} (to see whether to get new mail for
+this back end); and @var{back-end}@code{-group-alist} and
+@var{back-end}@code{-active-file} to generate the new active file.
+@var{back-end}@code{-group-alist} should be a group-active alist, like
this:
@example
BNF definition of a score file:
@example
-score-file = "" / "(" *element ")"
-element = rule / atom
-rule = string-rule / number-rule / date-rule
-string-rule = "(" quote string-header quote space *string-match ")"
-number-rule = "(" quote number-header quote space *number-match ")"
-date-rule = "(" quote date-header quote space *date-match ")"
-quote = <ascii 34>
-string-header = "subject" / "from" / "references" / "message-id" /
- "xref" / "body" / "head" / "all" / "followup"
-number-header = "lines" / "chars"
-date-header = "date"
-string-match = "(" quote <string> quote [ "" / [ space score [ "" /
- space date [ "" / [ space string-match-t ] ] ] ] ] ")"
-score = "nil" / <integer>
-date = "nil" / <natural number>
-string-match-t = "nil" / "s" / "substring" / "S" / "Substring" /
- "r" / "regex" / "R" / "Regex" /
- "e" / "exact" / "E" / "Exact" /
- "f" / "fuzzy" / "F" / "Fuzzy"
-number-match = "(" <integer> [ "" / [ space score [ "" /
- space date [ "" / [ space number-match-t ] ] ] ] ] ")"
-number-match-t = "nil" / "=" / "<" / ">" / ">=" / "<="
-date-match = "(" quote <string> quote [ "" / [ space score [ "" /
- space date [ "" / [ space date-match-t ] ] ] ] ")"
-date-match-t = "nil" / "at" / "before" / "after"
-atom = "(" [ required-atom / optional-atom ] ")"
-required-atom = mark / expunge / mark-and-expunge / files /
- exclude-files / read-only / touched
-optional-atom = adapt / local / eval
-mark = "mark" space nil-or-number
-nil-or-number = "nil" / <integer>
-expunge = "expunge" space nil-or-number
+score-file = "" / "(" *element ")"
+element = rule / atom
+rule = string-rule / number-rule / date-rule
+string-rule = "(" quote string-header quote space *string-match ")"
+number-rule = "(" quote number-header quote space *number-match ")"
+date-rule = "(" quote date-header quote space *date-match ")"
+quote = <ascii 34>
+string-header = "subject" / "from" / "references" / "message-id" /
+ "xref" / "body" / "head" / "all" / "followup"
+number-header = "lines" / "chars"
+date-header = "date"
+string-match = "(" quote <string> quote [ "" / [ space score [ "" /
+ space date [ "" / [ space string-match-t ] ] ] ] ] ")"
+score = "nil" / <integer>
+date = "nil" / <natural number>
+string-match-t = "nil" / "s" / "substring" / "S" / "Substring" /
+ "r" / "regex" / "R" / "Regex" /
+ "e" / "exact" / "E" / "Exact" /
+ "f" / "fuzzy" / "F" / "Fuzzy"
+number-match = "(" <integer> [ "" / [ space score [ "" /
+ space date [ "" / [ space number-match-t ] ] ] ] ] ")"
+number-match-t = "nil" / "=" / "<" / ">" / ">=" / "<="
+date-match = "(" quote <string> quote [ "" / [ space score [ "" /
+ space date [ "" / [ space date-match-t ] ] ] ] ")"
+date-match-t = "nil" / "at" / "before" / "after"
+atom = "(" [ required-atom / optional-atom ] ")"
+required-atom = mark / expunge / mark-and-expunge / files /
+ exclude-files / read-only / touched
+optional-atom = adapt / local / eval
+mark = "mark" space nil-or-number
+nil-or-number = "nil" / <integer>
+expunge = "expunge" space nil-or-number
mark-and-expunge = "mark-and-expunge" space nil-or-number
-files = "files" *[ space <string> ]
-exclude-files = "exclude-files" *[ space <string> ]
-read-only = "read-only" [ space "nil" / space "t" ]
-adapt = "adapt" [ space "ignore" / space "t" / space adapt-rule ]
-adapt-rule = "(" *[ <string> *[ "(" <string> <integer> ")" ] ")"
-local = "local" *[ space "(" <string> space <form> ")" ]
-eval = "eval" space <form>
-space = *[ " " / <TAB> / <NEWLINE> ]
+files = "files" *[ space <string> ]
+exclude-files = "exclude-files" *[ space <string> ]
+read-only = "read-only" [ space "nil" / space "t" ]
+adapt = "adapt" [ space "ignore" / space "t" / space adapt-rule ]
+adapt-rule = "(" *[ <string> *[ "(" <string> <integer> ")" ] ")"
+local = "local" *[ space "(" <string> space <form> ")" ]
+eval = "eval" space <form>
+space = *[ " " / <TAB> / <NEWLINE> ]
@end example
Any unrecognized elements in a score file should be ignored, but not
@subsection Various File Formats
@menu
-* Active File Format:: Information on articles and groups available.
-* Newsgroups File Format:: Group descriptions.
+* Active File Format:: Information on articles and groups available.
+* Newsgroups File Format:: Group descriptions.
@end menu
@example
active = *group-line
-group-line = group space high-number space low-number space flag <NEWLINE>
+group-line = group spc high-number spc low-number spc flag <NEWLINE>
group = <non-white-space string>
-space = " "
+spc = " "
high-number = <non-negative integer>
low-number = <positive integer>
flag = "y" / "n" / "m" / "j" / "x" / "=" group
Believe it or not, but some people who use Gnus haven't really used
Emacs much before they embarked on their journey on the Gnus Love Boat.
-If you are one of those unfortunates whom ``@kbd{M-C-a}'', ``kill the
+If you are one of those unfortunates whom ``@kbd{C-M-a}'', ``kill the
region'', and ``set @code{gnus-flargblossen} to an alist where the key
is a regexp that is used for matching on the group name'' are magical
phrases with little or no meaning, then this appendix is for you. If
cat instead.
@menu
-* Keystrokes:: Entering text and executing commands.
-* Emacs Lisp:: The built-in Emacs programming language.
+* Keystrokes:: Entering text and executing commands.
+* Emacs Lisp:: The built-in Emacs programming language.
@end menu
to the left hand side of the keyboard, usually on the bottom row.
Now, us Emacs people don't say ``press the meta-control-m key'',
-because that's just too inconvenient. We say ``press the @kbd{M-C-m}
+because that's just too inconvenient. We say ``press the @kbd{C-M-m}
key''. @kbd{M-} is the prefix that means ``meta'' and ``C-'' is the
prefix that means ``control''. So ``press @kbd{C-k}'' means ``press
down the control key, and hold it down while you press @kbd{k}''.
-``Press @kbd{M-C-k}'' means ``press down and hold down the meta key and
+``Press @kbd{C-M-k}'' means ``press down and hold down the meta key and
the control key and then press @kbd{k}''. Simple, ay?
This is somewhat complicated by the fact that not all keyboards have a
@end iflatex
@end iftex
+@c Local Variables:
+@c mode: texinfo
+@c coding: iso-8859-1
@c End:
-% LocalWords: Backend BNF mucho Backends backends detailmenu cindex kindex kbd
+% LocalWords: BNF mucho detailmenu cindex kindex kbd
% LocalWords: findex Gnusae vindex dfn dfn samp nntp setq nnspool nntpserver
-% LocalWords: nnmbox backend newusers Blllrph NEWGROUPS dingnusdingnusdingnus
+% LocalWords: nnmbox newusers Blllrph NEWGROUPS dingnusdingnusdingnus
% LocalWords: pre fab rec comp nnslashdot regex ga ga sci nnml nnbabyl nnmh
% LocalWords: nnfolder emph looong eld newsreaders defun init elc pxref
--- /dev/null
+@WITH_FONTS_bembo@\usepackage{bembo}
+@WITH_FONTS_pfu@\newcommand{\gnusselectttfont}{\fontfamily{pfu}\fontsize{10pt}{10}\selectfont}
+@WITH_FONTS_bcr@\def\verbatim@font{\fontfamily{bcr}\fontsize{10pt}{10}\selectfont}
+@WITHOUT_FONTS_pfu@\newcommand{\gnusselectttfont}{\fontfamily{cmss}\fontsize{10pt}{10}\selectfont\hyphenchar\font45}
+
+\newcommand{\gnususefonts}{@USE_FONTS@}
+
+%%% Local Variables:
+%%% mode: latex
+%%% TeX-master: t
+%%% End:
--- /dev/null
+%!PS-Adobe-2.0 EPSF-1.2
+%%Creator: Adobe Illustrator 88(TM) format generated by CorelTRACE Version 2.0C
+%%Title: /home/menja/c/larsi/gnus.eps
+%%BoundingBox: 17 11 127 122
+%%CreationDate: Tue Feb 20 01:51:37 1996
+%%DocumentFonts:
+%%ColorUsage: B & W
+%%TileBox: 17 11 127 122
+%%EndComments
+% Copyright 1992 Corel Corporation.
+
+% All rights reserved.
+.15 .15 scale
+
+/wPSMDict 150 dict def
+wPSMDict begin
+/bd {bind def} bind def
+/ld {load def} bd
+/xd {exch def} bd
+/_ null def
+/$c 0 def
+/$m 0 def
+/$y 0 def
+/$k 0 def
+/$t 1 def
+/$n _ def
+/$o 0 def
+/$C 0 def
+/$M 0 def
+/$Y 0 def
+/$K 0 def
+/$T 1 def
+/$N _ def
+/$O 0 def
+/$h false def
+/$al 0 def
+/$tr 0 def
+/$le 0 def
+/$lx 0 def
+/$ly 0 def
+/$ctm matrix currentmatrix def
+/@cp /closepath ld
+/@gs /gsave ld
+/@gr /grestore ld
+/@MN {2 copy le{pop}{exch pop}ifelse}bd
+/setcmykcolor where {pop}{/setcmykcolor{4 1 roll
+3 {3 index add 1 @MN 1 exch sub 3 1 roll} repeat
+setrgbcolor
+pop}bd}ifelse
+/@tc{dup 1 ge{pop}{4 {dup
+6 -1 roll
+mul
+exch}repeat
+pop}ifelse}bd
+/@scc{$c $m $y $k $t @tc setcmykcolor true}bd
+/@SCC{$C $M $Y $K $T @tc setcmykcolor true}bd
+/@sm{/$ctm $ctm currentmatrix def}bd
+/x {/$t xd /$n xd
+/$k xd /$y xd /$m xd /$c xd}bd
+/X {/$T xd /$N xd
+/$K xd /$Y xd /$M xd /$C xd}bd
+/g {1 exch sub 0 0 0
+4 -1 roll
+_ 1 x}bd
+/G {1 exch sub 0 0 0
+4 -1 roll
+_ 1 X}bd
+/k {_ 1 x}bd
+/K {_ 1 X}bd
+/d /setdash ld
+/i {dup 0 ne {setflat} {pop} ifelse}bd
+/j /setlinejoin ld
+/J /setlinecap ld
+/M /setmiterlimit ld
+/w /setlinewidth ld
+/O {/$o xd}bd
+/R {/$O xd}bd
+/c /curveto ld
+/C /c ld
+/l /lineto ld
+/L /l ld
+/m /moveto ld
+/n /newpath ld
+/N /newpath ld
+/F {@scc{eofill}if n} bd
+/f {@cp F}bd
+/S {@SCC{stroke}if n} bd
+/s {@cp
+S}bd
+/B {@gs F @gr
+S}bd
+/b {@cp B }bd
+/u {}bd
+/U {}bd
+%%EndProlog
+%%BeginSetup
+%%EndSetup
+1 i
+2 J
+0 j
+4 M
+[]0 d
+
+%%Note: traced as Normal_Outline
+0 g
+259.2 78.2 m
+327.3 178.5 L
+327.8 179.0 328.3 180.0 329.7 180.4 C
+373.4 241.9 L
+388.8 263.5 L
+389.2 264.0 390.7 264.4 391.6 265.4 C
+413.7 298.0 453.6 351.8 468.0 404.6 C
+467.5 405.6 467.5 407.0 467.5 407.0 C
+442.0 367.6 411.3 319.2 379.2 279.3 C
+372.0 267.3 366.7 265.9 361.9 254.8 C
+333.1 216.0 L
+323.5 207.3 311.0 185.2 302.8 175.6 C
+298.0 165.6 293.2 164.1 288.9 154.0 C
+282.2 147.8 282.2 139.6 276.4 132.4 C
+258.2 77.7 L
+258.2 77.7 259.2 78.2 259.2 78.2 C
+f
+0 g
+470.8 211.6 m
+470.8 211.6 472.3 212.1 472.3 212.1 C
+518.8 305.2 L
+531.3 317.2 L
+537.6 314.8 539.0 300.9 548.6 301.9 C
+555.8 301.9 554.8 302.8 561.6 306.2 C
+595.2 357.1 L
+595.6 358.0 597.6 358.5 598.5 360.0 C
+615.8 398.4 650.8 450.7 657.6 483.8 C
+658.0 486.2 658.0 488.1 658.0 489.6 C
+654.2 489.1 656.1 485.2 650.4 479.5 C
+634.5 446.8 611.5 402.2 592.8 377.2 C
+588.0 370.0 581.7 365.7 577.4 358.5 C
+570.2 355.6 568.3 351.3 560.1 356.6 C
+554.8 360.0 553.9 364.8 550.0 370.0 C
+548.1 371.5 550.0 370.5 547.2 371.0 C
+541.4 365.2 L
+511.2 319.6 484.3 276.0 471.8 220.3 C
+470.8 215.5 471.3 215.5 469.4 212.1 C
+469.4 212.1 470.8 211.6 470.8 211.6 C
+f
+0 g
+731.0 292.8 m
+756.0 351.3 751.6 407.0 771.3 468.0 C
+783.3 520.8 809.7 582.2 822.2 635.0 C
+829.4 684.4 855.8 732.0 825.1 789.1 C
+811.6 797.7 799.6 805.4 784.8 802.0 C
+757.9 792.0 732.9 743.0 726.2 712.8 C
+727.6 708.4 727.2 707.0 730.0 704.6 C
+731.0 704.1 732.9 704.1 734.4 704.6 C
+737.2 709.9 L
+754.0 747.3 L
+758.8 755.0 771.8 754.0 781.9 751.2 C
+788.1 748.3 791.5 745.9 797.7 744.0 C
+831.8 680.1 800.6 611.0 784.3 542.8 C
+765.6 478.5 748.3 431.5 739.2 370.5 C
+733.9 347.5 729.1 318.7 730.0 292.8 C
+730.0 292.8 731.0 292.8 731.0 292.8 C
+f
+0 g
+434.4 462.7 m
+460.3 496.8 462.2 532.8 458.4 575.5 C
+456.4 588.0 451.2 599.0 445.4 609.1 C
+435.3 620.1 435.3 622.5 421.9 630.7 C
+411.8 619.6 398.4 604.8 391.6 586.0 C
+393.6 581.7 396.4 584.1 401.7 577.9 C
+403.2 577.4 404.6 576.9 404.6 576.9 C
+407.0 574.5 406.0 573.6 410.4 571.2 C
+414.2 564.0 418.5 558.2 424.3 545.7 C
+437.2 526.5 428.1 489.6 433.9 462.2 C
+433.9 462.2 434.4 462.7 434.4 462.7 C
+f
+0 g
+226.0 482.4 m
+281.7 485.7 311.0 531.3 357.1 565.9 C
+362.8 572.1 364.8 574.0 368.6 580.3 C
+368.6 581.7 369.1 582.7 369.6 584.6 C
+370.0 585.6 371.5 587.0 372.9 588.0 C
+381.6 606.2 L
+377.2 605.2 374.8 602.8 371.0 597.6 C
+346.0 576.4 316.8 552.0 289.9 536.1 C
+288.9 535.2 288.0 534.2 288.0 534.2 C
+273.6 528.0 263.5 527.5 247.6 530.8 C
+242.4 535.2 239.0 536.1 238.0 544.3 C
+239.5 572.1 266.8 600.0 281.2 624.9 C
+293.7 637.9 300.4 650.4 311.5 668.1 C
+312.0 669.1 313.9 669.6 314.8 671.0 C
+319.6 679.6 L
+319.6 680.1 319.6 681.6 319.2 682.0 C
+285.6 649.4 258.7 601.4 229.9 555.8 C
+216.4 529.9 205.4 511.2 210.2 491.0 C
+212.6 483.8 218.8 484.8 226.0 482.4 C
+f
+0 g
+624.9 600.4 m
+645.1 606.2 L
+676.3 622.5 694.5 658.0 710.8 698.4 C
+710.4 704.1 711.3 704.6 712.3 709.4 C
+696.9 685.9 693.6 667.6 662.4 653.7 C
+654.7 651.3 649.4 650.4 639.3 650.8 C
+633.1 654.2 625.4 659.0 621.6 670.5 C
+597.6 620.6 L
+600.9 612.4 604.3 607.2 613.4 603.8 C
+617.2 603.3 621.1 601.4 624.9 600.4 C
+f
+0 g
+528.4 619.2 m
+548.6 617.2 564.9 629.2 578.8 645.6 C
+584.1 651.8 586.5 662.8 591.8 671.0 C
+593.2 681.6 603.8 690.2 601.9 704.1 C
+598.5 705.1 599.0 698.8 594.7 694.0 C
+581.7 679.6 L
+569.7 668.6 545.7 663.8 532.8 673.9 C
+487.2 697.9 467.5 754.5 413.2 772.8 C
+393.1 778.0 387.3 771.8 367.2 760.3 C
+360.9 755.5 357.6 744.9 351.3 740.6 C
+347.0 740.6 349.9 743.5 344.6 747.3 C
+344.1 748.8 343.6 750.2 343.6 750.2 C
+322.5 770.8 L
+312.9 775.2 300.9 784.3 287.0 779.0 C
+283.6 777.1 281.7 776.1 279.3 775.2 C
+250.0 750.7 229.4 705.6 181.4 697.4 C
+165.6 705.1 160.3 715.2 150.7 733.9 C
+130.5 685.4 L
+142.5 663.3 L
+147.3 661.9 147.3 660.4 151.2 655.6 C
+160.8 650.4 169.9 649.4 182.8 655.2 C
+212.1 676.8 L
+213.1 677.7 214.0 678.7 216.0 679.2 C
+238.5 695.5 250.5 727.6 279.3 735.3 C
+296.1 727.2 312.4 715.6 326.8 695.5 C
+330.2 688.3 331.6 684.9 335.5 681.1 C
+345.1 694.5 352.8 717.6 372.9 721.9 C
+423.3 726.7 453.6 670.5 498.2 631.6 C
+510.7 624.4 517.4 621.1 528.4 619.2 C
+f
+%%Trailer
+end
+showpage
-% -*- mode: latex; TeX-master: "refcard.tex" -*-
- % include file for the Gnus refcard and booklet
+%% include file for the Gnus refcard and booklet
+%%
\newlength{\keycolwidth}
\newenvironment{keys}[1]% #1 is the widest key
{\nopagebreak%\noindent%
\settowidth{\keycolwidth}{#1}%
\addtolength{\keycolwidth}{\tabcolsep}%
\addtolength{\keycolwidth}{-\columnwidth}%
- \begin{tabular}{@{}l@{\hspace{\tabcolsep}}p{-\keycolwidth}@{}}}%
- {\end{tabular}\\}
+ \begin{supertabular}{@{}l@{\hspace{\tabcolsep}}p{-\keycolwidth}@{}}}%
+ {\end{supertabular}\\}
- % uncomment the first definition if you do not want pagebreaks in maps
- %\newcommand{\esamepage}{\samepage}
+%% uncomment the first definition if you do not want pagebreaks in maps
+%%\newcommand{\esamepage}{\samepage}
\newcommand{\esamepage}{}
\newcommand*{\B}[1]{{\bf#1})} % bold l)etter
\newcommand*{\Logo}[1]{\centerline{%
\makebox[\logoscale\logowidth][l]{\vbox to \logoscale\logoheight
- {\vfill\special{psfile=gnuslogo.#1}}\vspace{-\baselineskip}}}}
+ {\vfill\epsfig{figure=gnuslogo-#1}}\vspace{-\baselineskip}}}}
\newcommand{\Copyright}{%
\begin{center}
Copyright \copyright\ 1995 Free Software Foundation, Inc.\\*
- Copyright \copyright\ 1995 \author.\\*
+ Copyright \copyright\ 1995 Vladimir Alexiev
+ $<$vladimir@cs.ualberta.ca$>$.\\*
Copyright \copyright\ 2000 Felix Natter $<$fnatter@gmx.net$>$.\\*
+ Copyright \copyright\ 2001 \author.\\*
Created from the Gnus manual Copyright \copyright\ 1994 Lars Magne
Ingebrigtsen.\\*
and the Emacs Help Bindings feature (C-h b).\\*
\quad [score] An article score. If no prefix is given,
`gnus-summary-default-score' is used. \\*[\baselineskip]
% some keys
- \begin{keys}{C-c C-i}
+ Gnus startup-commands:
+ \begin{keys}{M-x gnus-unplugged}
M-x gnus & start Gnus. \\
- M-x gnus-no-server & start Gnus without trying to connect to server
+ M-x gnus-no-server & start Gnus without connecting to server
(i.e. to read mail). \\
- M-x gnus-unplugged & start Gnus in \texttt{unplugged}-mode
- (first see the manual, C-c C-i g Gnus Unplugged RET).\\
+ \end{keys}
+ Additionally, there are the two commands \texttt{gnus-plugged} and
+ \texttt{gnus-unplugged}, which are only used if you want to download
+ news and/or read previously downloaded news offline (see C-c C-i g Gnus
+ Unplugged RET). Note: \texttt{gnus-no-server} ignores the stuff in
+ \texttt{gnus-agent-directory}, and thus does not allow you to use Gnus
+ Unplugged.
%
+ \begin{keys}{C-c C-i}
C-c C-i & Go to the Gnus online {\bf info}.\\
C-c C-b & Send a Gnus {\bf bug} report.\\
\end{keys}
\newcommand{\ArticleModeGeneral}{%
{\esamepage
- The normal navigation keys work in Article mode. Some additional keys are:\\*
+ The normal navigation keys work in Article mode. Some additional keys are:\\
\begin{keys}{C-c RET}
C-c \^{} & Get the article with the Message-ID near point.\\
C-c RET & Send reply to address near point.\\
/v & Limit to score. [score]\\
/E & (M S) Include all expunged articles in the limit.\\
/D & Include all dormant articles in the limit.\\
- /* & Include all cached articles in the limit.\\
+ /* & Limit to cached articles.\\
+ Y C & Include all cached articles in the limit.\\
/d & Exclude all dormant articles from the limit.\\
/M & Exclude all marked articles.\\
/T & Include all articles from the current thread in the limit.\\
\newcommand{\MsgCompositionMML}{%
{\esamepage
- \begin{keys}{M-m P}
- M-m f & (C-c C-a) Attach \textbf{file}.\\
- M-m b & Attach contents of \textbf{buffer}.\\
- M-m e & Attach \textbf{external} file (ftp..).\\
- M-m P & Create MIME-\textbf{preview} (new buffer).\\
- M-m v & \textbf{Validate} article.\\
- M-m p & Insert \textbf{part}.\\
- M-m m & Insert \textbf{multi}-part.\\
- M-m q & \textbf{Quote} region.\\
- % TODO: narrow headers (M-m n) ?
+ \begin{keys}{C-c C-m P}
+ C-c C-m f & (C-c C-a) Attach \textbf{file}.\\
+ C-c C-m b & Attach contents of \textbf{buffer}.\\
+ C-c C-m e & Attach \textbf{external} file (ftp..).\\
+ C-c C-m P & Create MIME-\textbf{preview} (new buffer).\\
+ C-c C-m v & \textbf{Validate} article.\\
+ C-c C-m p & Insert \textbf{part}.\\
+ C-c C-m m & Insert \textbf{multi}-part.\\
+ C-c C-m q & \textbf{Quote} region.\\
+ % TODO: narrow headers (C-c C-m n) ?
\end{keys}
}
}
\end{keys}
}
}
+
+%%% Local Variables:
+%%% mode: latex
+%%% TeX-master: "refcard.tex"
+%%% End:
--- /dev/null
+P2
+11 11
+242
+122 122 122 122 122 122 122 122 122 122 122
+122 122 122 122 122 122 122 122 122 122 122
+122 122 122 122 122 122 122 122 122 122 122
+122 122 122 122 122 122 122 122 122 122 122
+122 122 122 122 122 122 122 122 122 122 122
+122 122 122 122 122 122 122 122 122 122 122
+122 122 122 122 122 122 122 122 122 122 122
+122 122 122 122 122 122 122 122 122 122 122
+122 122 122 122 122 122 122 122 122 122 122
+122 122 122 122 122 122 122 122 122 122 122
+122 122 122 122 122 122 122 122 122 122 122
--- /dev/null
+P2
+5 5
+50
+26 26 26 26 26
+26 26 26 26 26
+26 26 26 26 26
+26 26 26 26 26
+26 26 26 26 26
(defun infohack-remove-unsupported ()
(goto-char (point-min))
(while (re-search-forward "@\\(end \\)?ifnottex" nil t)
- (replace-match "")))
+ (replace-match ""))
+ (goto-char (point-min))
+ (while (search-forward "\n@iflatex\n" nil t)
+ (delete-region (1+ (match-beginning 0))
+ (search-forward "\n@end iflatex\n"))))
(defun infohack (file)
(let ((dest-directory default-directory)
- (max-lisp-eval-depth (max max-lisp-eval-depth 600)))
+ (max-lisp-eval-depth (max max-lisp-eval-depth 600))
+ coding-system)
(find-file file)
+ (setq buffer-read-only nil)
+ (setq coding-system buffer-file-coding-system)
(infohack-remove-unsupported)
(texinfo-every-node-update)
(texinfo-format-buffer t) ;; Don't save any file.
(setq buffer-file-name
(expand-file-name (file-name-nondirectory buffer-file-name)
default-directory))
+ (setq buffer-file-coding-system coding-system)
(if (> (buffer-size) 100000)
(Info-split))
(save-buffer)))
This file documents Message, the Emacs message composition mode.
-Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.1 or
@node Header Commands
@section Header Commands
-All these commands move to the header in question. If it doesn't exist,
-it will be inserted.
+All these commands move to the header in question (except for the
+@samp{Importance:} related commands). If it doesn't exist, it will be
+inserted.
@table @kbd
@findex message-goto-summary
Go to the @code{Summary} header (@code{message-goto-summary}).
+@item C-c C-f C-i
+@kindex C-c C-f C-i
+@findex message-insert-or-toggle-importance
+This inserts the @samp{Importance:} header with a value of
+@samp{high}. This header is used to signal the importance of the
+message to the receiver. If the header is already present in the
+buffer, it cycles between the three valid values according to RFC
+1376: @samp{low}, @samp{normal} and @samp{high}.
+
+@item M-x message-insert-importance-high
+@kindex M-x message-insert-importance-high
+@findex message-insert-importance-high
+Insert a @samp{Importance:} header with a value of @samp{high},
+deleting headers if necessary.
+
+@item M-x message-insert-importance-low
+@kindex M-x message-insert-importance-low
+@findex message-insert-importance-low
+Insert a @samp{Importance:} header with a value of @samp{low},
+deleting headers if necessary.
+
@end table
@findex message-goto-signature
Move to the signature of the message (@code{message-goto-signature}).
+@item C-a
+@kindex C-a
+@findex message-beginning-of-line
+If at beginning of header value, go to beginning of line, else go to
+beginning of header value. (The header value comes after the header
+name and the colon.)
+
@end table
Yank the message that's being replied to into the message buffer
(@code{message-yank-original}).
-@item C-c M-C-y
-@kindex C-c M-C-y
+@item C-c C-M-y
+@kindex C-c C-M-y
@findex message-yank-buffer
Prompt for a buffer name and yank the contents of that buffer into the
message buffer (@code{message-yank-buffer}).
@end table
-@table @code
-@item message-ignored-cited-headers
-@vindex message-ignored-cited-headers
-All headers that match this regexp will be removed from yanked
-messages. The default is @samp{.}, which means that all headers will be
-removed.
-
-@item message-cite-prefix-regexp
-@vindex message-cite-prefix-regexp
-Regexp matching the longest possible citation prefix on a line.
-
-@item message-citation-line-function
-@vindex message-citation-line-function
-Function called to insert the citation line. The default is
-@code{message-insert-citation-line}, which will lead to citation lines
-that look like:
-
-@example
-Hallvard B Furuseth <h.b.furuseth@@usit.uio.no> writes:
-@end example
-
-Point will be at the beginning of the body of the message when this
-function is called.
-
-@item message-yank-prefix
-@vindex message-yank-prefix
-@cindex yanking
-@cindex quoting
-When you are replying to or following up an article, you normally want
-to quote the person you are answering. Inserting quoted text is done by
-@dfn{yanking}, and each quoted line you yank will have
-@code{message-yank-prefix} prepended to it. The default is @samp{> }.
-
-@item message-indentation-spaces
-@vindex message-indentation-spaces
-Number of spaces to indent yanked messages.
-
-@item message-cite-function
-@vindex message-cite-function
-@findex message-cite-original
-@findex sc-cite-original
-@findex message-cite-original-without-signature
-@cindex Supercite
-Function for citing an original message. The default is
-@code{message-cite-original}, which simply inserts the original message
-and prepends @samp{> } to each line.
-@code{message-cite-original-without-signature} does the same, but elides
-the signature. You can also set it to @code{sc-cite-original} to use
-Supercite.
-
-@item message-indent-citation-function
-@vindex message-indent-citation-function
-Function for modifying a citation just inserted in the mail buffer.
-This can also be a list of functions. Each function can find the
-citation between @code{(point)} and @code{(mark t)}. And each function
-should leave point and mark around the citation text as modified.
-
-@item message-signature
-@vindex message-signature
-String to be inserted at the end of the message buffer. If @code{t}
-(which is the default), the @code{message-signature-file} file will be
-inserted instead. If a function, the result from the function will be
-used instead. If a form, the result from the form will be used instead.
-If this variable is @code{nil}, no signature will be inserted at all.
-
-@item message-signature-file
-@vindex message-signature-file
-File containing the signature to be inserted at the end of the buffer.
-The default is @samp{~/.signature}.
-
-@end table
-
-Note that RFC1036bis says that a signature should be preceded by the three
-characters @samp{-- } on a line by themselves. This is to make it
-easier for the recipient to automatically recognize and process the
-signature. So don't remove those characters, even though you might feel
-that they ruin your beautiful design, like, totally.
-
-Also note that no signature should be more than four lines long.
-Including ASCII graphics is an efficient way to get everybody to believe
-that you are silly and have nothing important to say.
-
@node MIME
@section MIME
@section Security
@cindex Security
@cindex S/MIME
+@cindex PGP
@cindex PGP/MIME
@cindex sign
@cindex encrypt
Using the MML language, Message is able to create digitally signed and
-digitally encrypted messages. Message (or rather MML) currently support
-PGP/MIME and S/MIME. Instructing MML to perform security operations on
-a MIME part is done using the @code{C-c C-m s} key map for signing and the
-@code{C-c C-m c} key map for encryption, as follows.
+digitally encrypted messages. Message (or rather MML) currently
+support PGP (RFC 1991), PGP/MIME (RFC 2015/3156) and S/MIME.
+Instructing MML to perform security operations on a MIME part is done
+using the @code{C-c C-m s} key map for signing and the @code{C-c C-m
+c} key map for encryption, as follows.
@table @kbd
Digitally sign current MIME part using S/MIME.
+@item C-c C-m s o
+@kindex C-c C-m s o
+@findex mml-secure-sign-pgp
+
+Digitally sign current MIME part using PGP.
+
@item C-c C-m s p
@kindex C-c C-m s p
@findex mml-secure-sign-pgp
Digitally encrypt current MIME part using S/MIME.
+@item C-c C-m c o
+@kindex C-c C-m c o
+@findex mml-secure-encrypt-pgp
+
+Digitally encrypt current MIME part using PGP.
+
@item C-c C-m c p
@kindex C-c C-m c p
@findex mml-secure-encrypt-pgpmime
The S/MIME support in Message (and MML) require OpenSSL. OpenSSL
perform the actual S/MIME sign/encrypt operations. OpenSSL can be found
-at @code{http://www.openssl.org/}. OpenSSL 0.9.6 and later should work.
+at @uref{http://www.openssl.org/}. OpenSSL 0.9.6 and later should work.
Version 0.9.5a cannot extract mail addresses from certificates, and it
insert a spurious CR character into MIME separators so you may wish to
avoid it if you would like to avoid being regarded as someone who send
@subsection Using PGP/MIME
PGP/MIME requires an external OpenPGP implementation, such as GNU
-Privacy Guard (@code{http://www.gnupg.org/}). It also requires an Emacs
+Privacy Guard (@uref{http://www.gnupg.org/}). It also requires an Emacs
interface to it, such as Mailcrypt (available from
-@code{http://www.nb.net/~lbudney/linux/software/mailcrypt.html}) or
+@uref{http://www.nb.net/~lbudney/linux/software/mailcrypt.html}) or
Florian Weimer's @code{gpg.el}.
Creating your own OpenPGP key is described in detail in the
@item M-RET
@kindex M-RET
-@kindex message-newline-and-reformat
+@findex message-newline-and-reformat
Insert four newlines, and then reformat if inside quoted text.
Here's an example:
* Mail Variables:: Other mail variables.
* News Headers:: Customizing news headers.
* News Variables:: Other news variables.
+* Insertion Variables:: Customizing how things are inserted.
* Various Message Variables:: Other message variables.
* Sending Variables:: Variables for sending.
* Message Buffers:: How Message names its buffers.
@item message-subject-re-regexp
@vindex message-subject-re-regexp
+@cindex Aw:
+@cindex Sv:
+@cindex Re:
Responses to messages have subjects that start with @samp{Re: }. This
is @emph{not} an abbreviation of the English word ``response'', but is
Latin, and means ``in response to''. Some illiterate nincompoops have
set this variable to a regexp that matches these prefixes. Myself, I
just throw away non-compliant mail.
+Here's an example of a value to deal with these headers when
+responding to a message:
+
+@lisp
+(setq message-subject-re-regexp
+ "^\\(\\(\\([Rr][Ee]\\|[Ss][Vv]\\|[Aa][Ww]\\): *\\)+\\))
+@end lisp
+
@item message-alternative-emails
@vindex message-alternative-emails
A regexp to match the alternative email addresses. The first matched
@table @code
@item message-send-mail-function
@vindex message-send-mail-function
-Function used to send the current buffer as mail. The default is
-@code{message-send-mail-with-sendmail}. If you prefer using MH
-instead, set this variable to @code{message-send-mail-with-mh}.
+@findex message-send-mail-with-sendmail
+@findex message-send-mail-with-mh
+@findex message-send-mail-with-qmail
+@findex smtpmail-send-it
+@findex feedmail-send-it
+Function used to send the current buffer as mail. The default is
+@code{message-send-mail-with-sendmail}. Other valid values include
+@code{message-send-mail-with-mh}, @code{message-send-mail-with-qmail},
+@code{smtpmail-send-it} and @code{feedmail-send-it}.
@item message-mh-deletable-headers
@vindex message-mh-deletable-headers
@end table
+@node Insertion Variables
+@section Insertion Variables
+
+@table @code
+@item message-ignored-cited-headers
+@vindex message-ignored-cited-headers
+All headers that match this regexp will be removed from yanked
+messages. The default is @samp{.}, which means that all headers will be
+removed.
+
+@item message-cite-prefix-regexp
+@vindex message-cite-prefix-regexp
+Regexp matching the longest possible citation prefix on a line.
+
+@item message-citation-line-function
+@vindex message-citation-line-function
+@cindex attribution line
+Function called to insert the citation line. The default is
+@code{message-insert-citation-line}, which will lead to citation lines
+that look like:
+
+@example
+Hallvard B Furuseth <h.b.furuseth@@usit.uio.no> writes:
+@end example
+
+Point will be at the beginning of the body of the message when this
+function is called.
+
+Note that Gnus provides a feature where clicking on `writes:' hides the
+cited text. If you change the citation line too much, readers of your
+messages will have to adjust their Gnus, too. See the variable
+@code{gnus-cite-attribution-suffix}. @xref{Article Highlighting, ,
+Article Highlighting, gnus}, for details.
+
+@item message-yank-prefix
+@vindex message-yank-prefix
+@cindex yanking
+@cindex quoting
+When you are replying to or following up an article, you normally want
+to quote the person you are answering. Inserting quoted text is done
+by @dfn{yanking}, and each line you yank will have
+@code{message-yank-prefix} prepended to it (except for quoted and
+empty lines which uses @code{message-yank-cited-prefix}). The default
+is @samp{> }.
+
+@item message-yank-cited-prefix
+@vindex message-yank-cited-prefix
+@cindex yanking
+@cindex cited
+@cindex quoting
+When yanking text from a article which contains no text or already
+cited text, each line will be prefixed with the contents of this
+variable. The default is @samp{>}. See also
+@code{message-yank-prefix}.
+
+@item message-indentation-spaces
+@vindex message-indentation-spaces
+Number of spaces to indent yanked messages.
+
+@item message-cite-function
+@vindex message-cite-function
+@findex message-cite-original
+@findex sc-cite-original
+@findex message-cite-original-without-signature
+@cindex Supercite
+Function for citing an original message. The default is
+@code{message-cite-original}, which simply inserts the original message
+and prepends @samp{> } to each line.
+@code{message-cite-original-without-signature} does the same, but elides
+the signature. You can also set it to @code{sc-cite-original} to use
+Supercite.
+
+@item message-indent-citation-function
+@vindex message-indent-citation-function
+Function for modifying a citation just inserted in the mail buffer.
+This can also be a list of functions. Each function can find the
+citation between @code{(point)} and @code{(mark t)}. And each function
+should leave point and mark around the citation text as modified.
+
+@item message-signature
+@vindex message-signature
+String to be inserted at the end of the message buffer. If @code{t}
+(which is the default), the @code{message-signature-file} file will be
+inserted instead. If a function, the result from the function will be
+used instead. If a form, the result from the form will be used instead.
+If this variable is @code{nil}, no signature will be inserted at all.
+
+@item message-signature-file
+@vindex message-signature-file
+File containing the signature to be inserted at the end of the buffer.
+The default is @samp{~/.signature}.
+
+@end table
+
+Note that RFC1036bis says that a signature should be preceded by the three
+characters @samp{-- } on a line by themselves. This is to make it
+easier for the recipient to automatically recognize and process the
+signature. So don't remove those characters, even though you might feel
+that they ruin your beautiful design, like, totally.
+
+Also note that no signature should be more than four lines long.
+Including ASCII graphics is an efficient way to get everybody to believe
+that you are silly and have nothing important to say.
+
+
@node Various Message Variables
@section Various Message Variables
newsgroups the article has been posted to will be inserted there. If
this variable is @code{nil}, no such courtesy message will be added.
The default value is @samp{"The following message is a courtesy copy of
-an article\nthat has been posted to %s as well.\n\n"}.
+an article\\nthat has been posted to %s as well.\\n\\n"}.
@end table
--- /dev/null
+%!PS-Adobe-2.0
+%%Creator: dvipsk 5.58f Copyright 1986, 1994 Radical Eye Software
+%%Pages: 1
+%%PageOrder: Ascend
+%%BoundingBox: 0 0 596 842
+%%DocumentFonts: cmcsc8 cmcsc10 cmcsc9
+%%DocumentPaperSizes: a4
+%%EndComments
+%DVIPSCommandLine: dvips -f
+%DVIPSParameters: dpi=300, compressed, comments removed
+%DVIPSSource: TeX output 1996.10.29:2011
+%%BeginProcSet: texc.pro
+/TeXDict 250 dict def TeXDict begin /N{def}def /B{bind def}N /S{exch}N
+/X{S N}B /TR{translate}N /isls false N /vsize 11 72 mul N /hsize 8.5 72
+mul N /landplus90{false}def /@rigin{isls{[0 landplus90{1 -1}{-1 1}
+ifelse 0 0 0]concat}if 72 Resolution div 72 VResolution div neg scale
+isls{landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div
+hsize mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul
+TR[matrix currentmatrix{dup dup round sub abs 0.00001 lt{round}if}
+forall round exch round exch]setmatrix}N /@landscape{/isls true N}B
+/@manualfeed{statusdict /manualfeed true put}B /@copies{/#copies X}B
+/FMat[1 0 0 -1 0 0]N /FBB[0 0 0 0]N /nn 0 N /IE 0 N /ctr 0 N /df-tail{
+/nn 8 dict N nn begin /FontType 3 N /FontMatrix fntrx N /FontBBox FBB N
+string /base X array /BitMaps X /BuildChar{CharBuilder}N /Encoding IE N
+end dup{/foo setfont}2 array copy cvx N load 0 nn put /ctr 0 N[}B /df{
+/sf 1 N /fntrx FMat N df-tail}B /dfs{div /sf X /fntrx[sf 0 0 sf neg 0 0]
+N df-tail}B /E{pop nn dup definefont setfont}B /ch-width{ch-data dup
+length 5 sub get}B /ch-height{ch-data dup length 4 sub get}B /ch-xoff{
+128 ch-data dup length 3 sub get sub}B /ch-yoff{ch-data dup length 2 sub
+get 127 sub}B /ch-dx{ch-data dup length 1 sub get}B /ch-image{ch-data
+dup type /stringtype ne{ctr get /ctr ctr 1 add N}if}B /id 0 N /rw 0 N
+/rc 0 N /gp 0 N /cp 0 N /G 0 N /sf 0 N /CharBuilder{save 3 1 roll S dup
+/base get 2 index get S /BitMaps get S get /ch-data X pop /ctr 0 N ch-dx
+0 ch-xoff ch-yoff ch-height sub ch-xoff ch-width add ch-yoff
+setcachedevice ch-width ch-height true[1 0 0 -1 -.1 ch-xoff sub ch-yoff
+.1 sub]/id ch-image N /rw ch-width 7 add 8 idiv string N /rc 0 N /gp 0 N
+/cp 0 N{rc 0 ne{rc 1 sub /rc X rw}{G}ifelse}imagemask restore}B /G{{id
+gp get /gp gp 1 add N dup 18 mod S 18 idiv pl S get exec}loop}B /adv{cp
+add /cp X}B /chg{rw cp id gp 4 index getinterval putinterval dup gp add
+/gp X adv}B /nd{/cp 0 N rw exit}B /lsh{rw cp 2 copy get dup 0 eq{pop 1}{
+dup 255 eq{pop 254}{dup dup add 255 and S 1 and or}ifelse}ifelse put 1
+adv}B /rsh{rw cp 2 copy get dup 0 eq{pop 128}{dup 255 eq{pop 127}{dup 2
+idiv S 128 and or}ifelse}ifelse put 1 adv}B /clr{rw cp 2 index string
+putinterval adv}B /set{rw cp fillstr 0 4 index getinterval putinterval
+adv}B /fillstr 18 string 0 1 17{2 copy 255 put pop}for N /pl[{adv 1 chg}
+{adv 1 chg nd}{1 add chg}{1 add chg nd}{adv lsh}{adv lsh nd}{adv rsh}{
+adv rsh nd}{1 add adv}{/rc X nd}{1 add set}{1 add clr}{adv 2 chg}{adv 2
+chg nd}{pop nd}]dup{bind pop}forall N /D{/cc X dup type /stringtype ne{]
+}if nn /base get cc ctr put nn /BitMaps get S ctr S sf 1 ne{dup dup
+length 1 sub dup 2 index S get sf div put}if put /ctr ctr 1 add N}B /I{
+cc 1 add D}B /bop{userdict /bop-hook known{bop-hook}if /SI save N @rigin
+0 0 moveto /V matrix currentmatrix dup 1 get dup mul exch 0 get dup mul
+add .99 lt{/QV}{/RV}ifelse load def pop pop}N /eop{SI restore userdict
+/eop-hook known{eop-hook}if showpage}N /@start{userdict /start-hook
+known{start-hook}if pop /VResolution X /Resolution X 1000 div /DVImag X
+/IE 256 array N 0 1 255{IE S 1 string dup 0 3 index put cvn put}for
+65781.76 div /vsize X 65781.76 div /hsize X}N /p{show}N /RMat[1 0 0 -1 0
+0]N /BDot 260 string N /rulex 0 N /ruley 0 N /v{/ruley X /rulex X V}B /V
+{}B /RV statusdict begin /product where{pop product dup length 7 ge{0 7
+getinterval dup(Display)eq exch 0 4 getinterval(NeXT)eq or}{pop false}
+ifelse}{false}ifelse end{{gsave TR -.1 .1 TR 1 1 scale rulex ruley false
+RMat{BDot}imagemask grestore}}{{gsave TR -.1 .1 TR rulex ruley scale 1 1
+false RMat{BDot}imagemask grestore}}ifelse B /QV{gsave newpath transform
+round exch round exch itransform moveto rulex 0 rlineto 0 ruley neg
+rlineto rulex neg 0 rlineto fill grestore}B /a{moveto}B /delta 0 N /tail
+{dup /delta X 0 rmoveto}B /M{S p delta add tail}B /b{S p tail}B /c{-4 M}
+B /d{-3 M}B /e{-2 M}B /f{-1 M}B /g{0 M}B /h{1 M}B /i{2 M}B /j{3 M}B /k{
+4 M}B /w{0 rmoveto}B /l{p -4 w}B /m{p -3 w}B /n{p -2 w}B /o{p -1 w}B /q{
+p 1 w}B /r{p 2 w}B /s{p 3 w}B /t{p 4 w}B /x{0 S rmoveto}B /y{3 2 roll p
+a}B /bos{/SS save N}B /eos{SS restore}B end
+%%EndProcSet
+%%BeginFont: cmcsc8
+% T1FMT-V2.0, Copyright (c) 1993,1994, Basil K. Malyshev. All rights reserved.
+12 dict begin
+/FontInfo 13 dict dup begin
+ /version (1.1/12-Nov-94) readonly def
+ /Notice (Copyright \(C\) 1994, Basil K. Malyshev. All Rights Reserved.\012BaKoMa Fonts Collection, Level-B.) readonly def
+ /FullName (cmcsc8) readonly def
+ /FamilyName (cmcsc8) readonly def
+ /Weight (Regular) readonly def
+ /ItalicAngle 0 def
+ /isFixedPitch false def
+ /UnderlinePosition -133 def
+ /UnderlineThickness 20 def
+ /Descender -194 def
+ /CapHeight 683 def
+ /XHeight 506 def
+ /Ascender 694 def
+end readonly def
+/FontName /cmcsc8 def
+/Encoding 256 array
+0 1 255 {1 index exch /.notdef put} for
+dup 32 /space put
+dup 33 /exclam put
+dup 34 /quotedblright put
+dup 35 /numbersign put
+dup 36 /dollar put
+dup 37 /percent put
+dup 38 /ampersand put
+dup 39 /quoteright put
+dup 40 /parenleft put
+dup 41 /parenright put
+dup 42 /asterisk put
+dup 43 /plus put
+dup 44 /comma put
+dup 45 /hyphen put
+dup 46 /period put
+dup 47 /slash put
+dup 48 /zero put
+dup 49 /one put
+dup 50 /two put
+dup 51 /three put
+dup 52 /four put
+dup 53 /five put
+dup 54 /six put
+dup 55 /seven put
+dup 56 /eight put
+dup 57 /nine put
+dup 58 /colon put
+dup 59 /semicolon put
+dup 60 /less put
+dup 61 /equal put
+dup 62 /greater put
+dup 63 /question put
+dup 64 /at put
+dup 65 /A put
+dup 66 /B put
+dup 67 /C put
+dup 68 /D put
+dup 69 /E put
+dup 70 /F put
+dup 71 /G put
+dup 72 /H put
+dup 73 /I put
+dup 74 /J put
+dup 75 /K put
+dup 76 /L put
+dup 77 /M put
+dup 78 /N put
+dup 79 /O put
+dup 80 /P put
+dup 81 /Q put
+dup 82 /R put
+dup 83 /S put
+dup 84 /T put
+dup 85 /U put
+dup 86 /V put
+dup 87 /W put
+dup 88 /X put
+dup 89 /Y put
+dup 90 /Z put
+dup 91 /bracketleft put
+dup 92 /quotedblleft put
+dup 93 /bracketright put
+dup 94 /circumflex put
+dup 95 /dotaccent put
+dup 96 /quoteleft put
+dup 97 /a put
+dup 98 /b put
+dup 99 /c put
+dup 100 /d put
+dup 101 /e put
+dup 102 /f put
+dup 103 /g put
+dup 104 /h put
+dup 105 /i put
+dup 106 /j put
+dup 107 /k put
+dup 108 /l put
+dup 109 /m put
+dup 110 /n put
+dup 111 /o put
+dup 112 /p put
+dup 113 /q put
+dup 114 /r put
+dup 115 /s put
+dup 116 /t put
+dup 117 /u put
+dup 118 /v put
+dup 119 /w put
+dup 120 /x put
+dup 121 /y put
+dup 122 /z put
+dup 123 /endash put
+dup 124 /emdash put
+dup 125 /hungarumlaut put
+dup 126 /tilde put
+dup 160 /space put
+dup 161 /Gamma put
+dup 162 /Delta put
+dup 163 /Theta put
+dup 164 /Lambda put
+dup 165 /Xi put
+dup 166 /Pi put
+dup 167 /Sigma put
+dup 168 /Upsilon put
+dup 169 /Phi put
+dup 170 /Psi put
+dup 173 /Omega put
+dup 174 /arrowup put
+dup 175 /arrowdown put
+dup 176 /quotesingle put
+dup 177 /exclamdown put
+dup 178 /questiondown put
+dup 179 /dotlessi put
+dup 180 /dotlessj put
+dup 181 /grave put
+dup 182 /acute put
+dup 183 /caron put
+dup 184 /breve put
+dup 185 /macron put
+dup 186 /ring put
+dup 187 /cedilla put
+dup 188 /germandbls put
+dup 189 /ae put
+dup 190 /oe put
+dup 191 /oslash put
+dup 192 /AE put
+dup 193 /OE put
+dup 194 /Oslash put
+dup 195 /suppress put
+dup 196 /dieresis put
+dup dup 161 10 getinterval 0 exch putinterval dup dup 173 23 getinterval 10 exch putinterval dup dup 127 exch 196 get put readonly def
+/PaintType 0 def
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0] readonly def
+/FontBBox [0 -250 1142 750] readonly def
+/UniqueID 4701552 def
+/StrokeWidth 0 def
+currentdict end
+currentfile eexec
+9B9C0887DB83FB1ECD8335B0BB39CEF0AF64F656FC6E5C230CC9D3A7346AAC7A
+06BD9A40393CA15D3773A21E06B9B4254D3050E90726BBB09120935A8D448CDB
+C799D90205A21291254FA633CC0C2ED88781EF21A5D45B72445C284FA44F8F39
+CF566976075A92E9E2947A6FC93D879C29EB26809ECB4409CBC8666526CCED92
+65DE661A2F8B0A16BE45A9DA17EEAF89B0E023DE2B0373DCAB997D60B7D7DC1B
+4F7E650A2A9F13CA0543F3B080AE33D65F2802B8C6F032ED6E6DCCE8BDCA96E0
+7ACBDA80BD4CD2ECDDBA9F2153A5830B911EF4A2B2759509074BBB7EF4647A84
+A7D80486A975F887C24E3B91C13DCA84013E21D22732074711E18BF909EB19E0
+17003B8DDC9A09B7DCA54C0683A0301A22EB83147467E02063122C43B4084720
+DD14D09F869DB8BF36651E182AB50EAABD5374B4765E7BB0DBBAA6F1745B0EAE
+3CD63C9913A9AB7ACA280E94078158263D7DA75FBA9944B33A681993B009FFEC
+04291CA8E1DCCAF55D1FB9B4C630E378EB500EA97B07B6F3F3A66820CA68656F
+AE47789E6C164A26FC1C2525E4247A4AE5D0B9202A92EE3090FB25093B2E68F4
+DDD3DC598A87914782AA1B79AA31505752F8A47D2DCB51ACF6EF0832B9C1020C
+2761DB6E6AB9749D4D7993682371D9BEE6684D1EFFCB0F1465672DB9769673E8
+2435B28D8BD3E4AECCBF2B127E146415B15066D39103B20C8B415B3C6A640FE3
+5934F1A1E8256A6FDF9208A56E65A7C94A960923889D592CCD9C94DE37C1448A
+09D876F58C506924D478BFE724329AF64157543A5263A8652FD2E852BC07FF57
+E438C93BCE2B0E219EC1A8E2C8A6DC708C990810A536877369A477D7E7D12355
+434A7A99CCECAA340329044B79B33AEA924E95AE898442A7FD06F7E73948F535
+A8556534730B981547A9ED3D5BBAD6AFD08BDC8FCAE6A46F63644D5BFE139A0D
+EA380C737C228832FCB4DCD0BB8208D3050E5CDF7C194835E9770D1F60F4B78D
+910E195BDC30653EE5BE7DACD166F2BEC6698CD2D355BD9605795E6EDA8462A2
+BA319945113FDF8DF0C629532064726133522021D21B033DFCA23EC2F71CA591
+2ED8FF78703FFB2422C2E38283AAA99B9A7BA72C3124957D172BBD55C6FEAB07
+6CCD143228A63253BA4BE92E32FCB72E150BD00CD5B2A1427B1C4901B0CE4479
+A763497DCE9904F4C02D440646725A28B897AA2524D9CD05C2A2F21919F22378
+88131B729ABF1FEFE219D93FC16C55C37CBF7DBEFF403220AF82CA530052F476
+7C140370CC7E73AF028A152494B4AE330BB66ADD4ABC6D74BA1CAAD743E9969C
+7EB9C94D56448B8C1A5D65199C45E746B8D9498C836043282600FF0A4AA0DA2A
+93362A65B9AC53679BBE3DF9C46A56B252C39D0E4C6C475AB50B0F6077DF0E51
+6E2B629AB0D7F4B8916309BBFD04EFEB53B2A887CD71E2F2E7C5546FFF3D6807
+2E1700F1FC8BA07F7DB6DA818D981284D05459161CB626165708B665399B0C44
+B20BDDD6FF4747C9539F3A9D1B2F6E198CA21D61F8030C56DB55B72210CEE1BD
+783030A32B7109F317B75885C90DED2ED25F1497F9BF7CB750618565D8B9F7BC
+B14D5770240396CD2D3E22225E76FD0222F2DE79615ED0EDFE19D7B8940BF147
+974EA060EDE6142D3A98E86F3BF92021D63BC13E79D2D7BF12C4285BC9805E0F
+B330DF7CFC283BD744CFA70BA34025E2F9C4F613B4AAD255F7D6493105253E37
+A88678147D7F1B600E611813BE2866B827ACF70FCFFC2BB331639D8B212D48B4
+285BB430B120820CF07C849B8C4742F60408D69E9E5A3A062DDD616AEA5D65F7
+B6BE3CD8672561678462F38142B6DA16BE3E8E1DA1C49E5E1E447F9068ED7813
+C406B262E01434885E0A0EB5EADCCD01D09229C801257F7C400EC7FA7384F138
+816CB2D68571A14FFE15DA71206EAB82A9CCF44CBEB5F1CF80EF5EDFAF70088E
+0315677C806D87112A0F1F5387204C2172B3551B48297EC3C0987EA47E561BB0
+D1A59CD20A0A8950420006CE3E8F2E89131ED3BF235753440A31322420321948
+50A91ABF95D81A7333903852994489482C760D8E6ABCB90D4BC76E59A7D77543
+18DF8DA712C2886272C388129B9DE91E139EAA28D4F8E628F66F8CB82EFC63B7
+4DE99680B0A40D2E8D27F2EFC4D3F84B5D4E2664438C23EADD2432A078F0615A
+1B168BE016AA5EB1BBAD70B50EB6BBDD98AA46035E177CA3B5D2C0B19430236D
+E42DD05E4C5CADAA36F9F2B59163C0AE31FCC8FF0ED40666E7C409F2DE49D54E
+9AD3AB0BA8DC7917A5A11D5553F3C5C3AA761C71AF6FA03E74FA0A8CBDC00C58
+5BC44EA557734457D1C3017BD8215486F4A912B6CD5B7F5293641CA5E18CE696
+94439509E39668443555D82D48982CD86A72307F9181561F4A48713B18F7F414
+D62BCC15ED2130C3C3A12147C340C5CF16441C6B1C287D2952EE64D4524C67EC
+6685D7110F55DF79006467C567F450C058C47495B54EC7D8AA9E54EAD272A6A6
+3985B7EFFC7F1374EF726AF07995774F42BB910F6B93275C81481E69CBB062D7
+48DFD3A8F7867FBC0777174D1645EFF68737E152BAFFCA6D11E9E047D23B5DC0
+AA510CB028F7BBAEA876B4D80A8863BB0307813D6CB051F001665EAB2AA77687
+F1E5381BC3A60884510091A6C8A065C5255CFF31CD5129A33EF4A2A1F29B0B29
+081076B795D99B052F5152231D63BC2542661943D1771CF0BBD5255851C467E3
+017AB1CF41E127F90AEB0D465E70DF088A1D1B72B8AE8DDD08E72B5C8CCB7CB9
+004B39BAD93E3E8D3EBC1254CE7C047788C46D9826E2C444F1E0FF2401FF7DF7
+6A202BC1878BBC6DCEC3B17DC323125E4D75024B4A08E92F0C1B97D9EBF895E4
+1E384FA8D6C66E19E39C8A26FD1E0E5A5905B152DD7F617058F9A880623A9B4E
+9F1737EC61D00C576ED8306ACB625E1AD85A809CDE751A34B83F04F89817D627
+E34844FD56719626BAF81FDF2BC4815F7AD55833E17021161AC6CA9B2393721A
+C39323754978C27F0A19D3DB3DC517D4322FB3B673C26B1FFB093590EB133DF2
+3D30AE05EA926A43FD3579EDB1E9D402203ED0A0694E258CFF6B136CFA2BF757
+E7EC2C9C1332B998DD86E7467F522883AB5E9D01C948402E3814415E0DF6362F
+D29616D861AB88D3AFF5EFF233552DCCB301AC00C57A8CC3A75544C3F1FA92D1
+D13888FDF0597E8EC842C0C6DAFFA6F5FD36AFD0EE385A87BCE628AD3C963B98
+5E66712EB1EBB886C8C7AAC776C41F4CD1D1B2F1207C2D0499E8911CF17EBF06
+DB261EF1A9F73C487D0B1AF98C26E3ADDE84678CE54F6877440511D21BFBE304
+98A6ACA6AA32775BE50C603EFC86509D1078AD952502E1E0ACBDBB1134F5DCDE
+4B423463E37FA01D0233C049CC9A61EC5A0A9373070CB6431798186C116145AC
+20AC07CA60DDD0CFAA838674E889ECBA7CDD700CC6FB02C4BF018A0675798A14
+BC3F97B7A0C256711C9983DD7C465364504C1C14C51288692FCD0DE3F26CA406
+7E4D7CFC45D7C4DDE97A61423185C0FE7B9960B396028B532D52016A497CE87B
+5A5B35136246646601B5BECE7E380F3F3A2EB428CDBEFD4EDB6018AE34A441DA
+7CFD700D66527EDDB47091A64696275096DF98B4B9178159A0FDADADE7515C26
+F97C12422D031F8D230FE2082B11AD582F2BD054053E2E8DA0F4DE167A354241
+F9758A06B11379CD99F3129DD37DCBCA5F765478D682110E848AF83E63B3EF27
+AD0F2F23CEF688EC5A4811D1E73292D940005DBF7DF19524E33593AA0CA9B030
+926DE55A6E8384D006632F5900D00F851708CB7EFA5D0B227DBEAE710F3CA02A
+890482C433ADDFACF2960EF914F9651A47FAD819A4C17FEFF30ADA059D9CAECA
+C143AA3E92AEADBA92D85BAF433344FC16EC00BCCC90DB42660EFB6EA2D68E42
+37D4083FEA72FEBC845C7814FD8F50A0687F93C26E32661D5C6C5888259FCDF5
+C70464929FA36D2E59FCE1AE85AC3C5D733726DC92600AE606C878CED4706F8B
+1ACFD0DCEC65DB23179B3E08E456AF6FDE3027C44F3CA86FD02D30E1FC8F3450
+BFFB18CACB0CA334D6D6C11B4DF63EDE14012995916E9965ACB3575ED07BEE18
+BCEE5D634EFA1E9DBED3817F10957D957900E6AC120D2A0578CEB6FE9888ED01
+BAE8869A8DD42E447E29BAAC8E025F63B64E90F055B7D3D7BA91914B55C58E1A
+E6F984CD73413E494BBE8F20A2030B92E103874B7854804744EA67F34BB32D26
+CEB4FFBBF4F5C53ADF745F9F2108F28E6E9BD346B677D7D81D29BE9D41EDC105
+AAAE4C65004BFC8ADE14673D816512A81C1720B2A4FDD19690303A284472BDCD
+23D6A1890FB40B476123038F1AF5D2679BEED1C037F5532D32202AA8BCE983C3
+AE95E4A4407AA55ED9365D8326B1BCD5977E4BF09DDF76423E94848331642C6A
+3E1F48AC45A3957638ED5E147DEC4C195EFAF416F2A9AB07765F972111D96271
+DF49CD50F562E18E44309B86079A015AEC2654F5D30E387C8222B264428A6C51
+AFB024147B909E6598AA3A6085234A6DF6EE4F8B7C6D9D5A4C7428E7634C13C9
+EBA54B692234201F6DE0DA56ED76D4951D0D89A53431B83089FE196262525784
+F218B390E3FDE1F7DF139E876887A4EC4C7C7337DE070482E60765358688BD73
+61B84BD08A31BF1AB5F833E155079A130F5039DC39970BDA24C9F89206D6BC13
+31BCE613202E817404403EAC748D4BE72CE82B4ED24E33A45F39091E0D33E7AE
+D961B0CEBF6A0187769F43BC921AE7FFCF3F933E8D4B6B0896B46FE843E0F783
+8D7531622D72B135F34F5DABAD6120E290CF281A38A1D22FC12FDF58C9655848
+B045CF758DB113D61303EF62C4D9228D58E60726921686B4DA64E64C970AFFCA
+63C0D672A9C28B88D1194AF22328E0A4DA9A65C11CB59B5F55F0CABE32AC729E
+119AA07D135D97C8FE90A213D466C5A02CB2E0CB78EC1EC67CADA027ED6588EA
+17410FF368DF29A2D36E0F2CD43DA29BF6E0BD9FCD56A0F509B4A1BB0D35BA2D
+E0A09400BD5E557058E3E168400F2F34E33CDC252E76FC7D252E8CED53A265BF
+02B05A11D432E17E5E496A14F7AF41AD237372C22D0FCA183DA4A87B191A282D
+ABBAA8C292E9CAEEB5722A98BF39639DA0232F80F624C667DFD9AA8C7B210401
+D65F6D88A8DD33211B1C58D12DE7A6024C6CE7F62C7530C050C35DBDB3E4B7AE
+8686CDBB7FC13D2A16A064A00AC7FA37B3DF11D5E6AB7B26D70F7097DD1A463C
+F199861DCB273D8BD27DA5E4C01F64D59D6C6301CF85F9C100F182EFE7824A0A
+AE6AD44811F9E31F21ABFF320823FF6416F9524C408BEF52D6565AFB590AF48B
+787BF5CC4ACD76DB049F807F4AE0C1410446960392EB1F897E308918ED11A2D2
+2165CA9DD631673F608D1D2594D8D2003E9EC77E8B4FBEFDBCD9114E39042556
+EDEB5D66C755966A1EF4607F283B0E604C7A611ED7FB30AFF1AC48A3C9E8443E
+AB020C1C274BD90D476076FD1D7119B80CA4BF14AEF63288C58C17D533935EEE
+C69CD5F16C27953155C5111E49A8F0BCED4F0638AA63424266037220120AE497
+28C1511E3CDDF8AAB7BD45E32ADB2368A111F4280FA7D77D4331C116578B34CD
+DF024F7ECCC04E2A79C5EE039A647AF7F8B6B50CF477CE0F1C6513FED5A4A28E
+6919C2507F0FB9B8A1FEAEF739FB2F76B27BC63148FA3893731CD2C07A2EAEF4
+32F8A9E0B60DCCBA2625203285DB22DFE6331D47114CFF282A832B49C6DFA41D
+EB713891FAFEFDDD35B8977035FECA00118D0B449C849807F3834AAC455ED857
+E44ECEC289E7C2A97D184E253C24D2DAA1E2D5B5A18DB7013A549C5ADDA2FB58
+AA6FC4E2BF2D66FA37F1D70BDA8BDE834FBF7492EC522A7E7CB1578C47497E16
+6D350795FD7A40BBE85C437B60605AFF8595DB6591BDF61C56588E774227E1E2
+EDDC27AEA4A1CB6EFEB85D4C9CB1BBC60AB12C6452BBD70796F443A86E797E15
+293E6CC2C90245FE60C8039B25DF068C08C0101CFD6D00D1F7035DBB0490C0A1
+30ED4BAB83002DDAF4AF4DD4D00DE5329C79120E11D962F896AAEA17FE0090C2
+7F72A7FAC06374FE210246CA064A418F41BF71DC8B24848D1C8FBB1B7DDBAA66
+E698FCF9C6772A48B2AE1A1C4B48E17BABC6F2ECACED6A2D93C1C88E25B24F35
+B2CEB9791B56FFFF0744D78789F08E6C18F2067B1333B65A1A7D0E17042EF669
+B654DE023F51138863C399367CAF2A24DBA556FC96EF83931B159EDD23936643
+5AC3AEB5B1B0D55970F95574AC6D28221B4C4A6EF2C79245D479B654999FE261
+35D105EB8238D449AA347D0E5C1DDF8E864D64F8B5A30B3BA8D45A056BD44EBA
+9D3187EB5A0DE2C180C23A7E67C9D4FC406DD2DD65311D4AEBB248F808250F62
+6554BCE687198D3C7F17E05A135CA32F78653917966DBB5CD1D0A5AC853D21C3
+6E12A327B2C266A6F6E68172B8CB7554EEE21FAEA90CA9B23C3522AAE3DA7A0D
+636DD7E95F360524FC45404491F77B86B4C556D291C43EBE93B02470C5AC926F
+DE1DF486C33410BA8A180C733198FF6D395CB1FACD0230AC8D4AA0BFED92EC39
+5854F3D9703A22B10797848921BC020ED3DCD1995FD7BB958B5D1C4EBDF64417
+0E6436D6627769786331A57EAD7F8CF003CF9F9B91D67CE861B914F6F76043AA
+F98C977CFDD7AE978DB14C1003EFD6E20758D14E89AB901583DD6FEF25AEC853
+2E605D4C061600A63CA2C6EE608E075EC86FDF5A59DF5097FC79C206307CA74F
+60C6973E73DC392464A7A367986E55E63BFA4E60FCE12CDAA7751875E2F986A0
+8C6E1B992F925FB8A36BC28A5F2A505E24BE752E7D88F8CFF3A0B9018598050F
+D3EC8E2188FBD2264C8676E9CDE54F6E1537BB7F3DC61330ED9E165E5285EFC5
+5209BD7A8AD120015F03A2CF3772FCD1B4AAFD01F080046EDF1970A5024698EA
+07CE1F1F98C272DA4DE32232520574727B76C1B1137F9F1934310E7CAFECC814
+27281B334C132764A015C4D1D1DEF7460AAD063228C346896105018A5F78CC4D
+AF70ECB26B0C210DBAFF76BF479920809C35120721B2BFE5E95C50CBF3892339
+A78088197FD12BB712138515CCF50D09C6790E0FA678EA80C9B73AAC450280B4
+F6FF5D55F85BF9FE7927F29E74CA6A7023C55D761E7312A842137079A0420095
+9E54938344973FA3F6AACF978E861C800C97103EA952113A79C0088557216D10
+F55EECA021975695F68E36E51F229AF292E40069A167DDB66EFD5E5E5B113F75
+DC4CAE95D6E2F2B46410FC0DF2EDB3C9E4525FB3035D276608805A2410F475C7
+C02FDB7627619F34510299C03E8EF22D82C0F0BA848E4D63DCEB84BC5239E860
+A01980A898E7406F2C2C2683D864182EB055D5401A6BE0C51CA23382A25F3B77
+96FA4AF27212794228074676D53CC7ADE248B87B6DEAA00653DC7515D5D68A12
+E3CAB1CC1D4828ED42132EE31BFA2454DB21DDAB9871588D40153E879CBAA641
+EC670FC30C476BC40843BC52D06B65D3E21206393419C2A3B80EFCAFB9A8D945
+A8865633F5480A44D9E54E4B30A0DEF43D2686ABA55FC2ABE38751ADA14AF090
+AA086B564CDF2AD272700CBE7014C34747EDB454A6E1C3D4F89C1864D12D00AB
+980A73884FB915D4BCD7AE17FD70414E1E4156CB64EBEE3C1F1B65C7C07FD457
+528024B5C5F54CF00F5B3003B7819D4F8D52C770B555A428C0D8AEB1ECB5E1AD
+56097BB4953D5C4F9071A781B59186C198EB18A55B23B88A8122151F14BBEEBD
+AC9F98F7F5C2C98544832514B5F55F38B007463783C8A35A17C3B9643C299D8A
+9B3B7B5AC937E5D84C3350FAE832D03EDF33C947001111FA191853F980F94A2F
+B0C1B5373E3D8D7812E56D0533CB81105634DBE5A3E1ADAE4892E63C6DD415DF
+94FC71C47D50B09A07240AD792B982D2EBE06B07A5DEAEB00111BA1E801D9D47
+A972E4CF59018FC24056BD3312E7F2F0767DD96DBEF430626B4BBB97B1B4795C
+A2A07F77E676C019F56BE0D97DE82D9FDB145B6F26B6158D61C308940B41EDDA
+49ED20605D0D8CAC1D388F9458C627A791E5D6E214F1BFBA154D0F8FB70FA297
+0E2B98DC3FCE351E8B9F0EE20FE6528856C02FE91DC5D83C8C52B3A1D7AB4025
+F5379C5A590570D228FBD7BDB243A9B95C6D156F7051930F0F112B57242EFCBB
+545A55D8568F3272D94BBDBB9B5DAB351C9940B42C11E1D2B860A2ADD4D9F914
+E4C1A513D3EC036D749DB0D652AE6AFD99C886BB65234E75E985ED5775595662
+B3953D1B90C2D841483A4D937352271E311C17ADD47FF0652EC281C30A7E00D5
+95FBD22A2D57B768B1A6402AC2BDA87049F299EF3BE8C76F8472901ECD10ECAE
+1F77615A9A76FDCB3ACFC8C1A0BBC9207CEDE059C11B452981DE849AA5361BF9
+EC51F7ACD2C1C3CF2E36C67AB294EC1DF145FDFB87D8FEE3CE8C6F744D089C5E
+8CAC6EF70BA2E6862F44F0792426E85DE0F2987AA239B371B00F3E2F4027079C
+11D40FC16ABF28EE96848C97B0CD695BEC0F961C96BC744DC6D7D08D2E1B9F97
+78DA68012F7E1DA1F2CA72000B4E807F22A0D77272E00F44478F1EE69882BD4E
+3C58EAD4BF9269DB275069750017D84B460772B9F25D6AD78D0B32A33FD9B748
+37E0E166FE9AF15EC12486939626FB4AF31D503F9DD3E71B1D31ABFCED334C4D
+F58A03DA6A641D5DF8D6E5CAD1927BDD0C9F32B970C4E7539089C66D107D8757
+31C513230C44FF66883CB7C46EBD1F635F8A2BEB78A08AEDFB8E165050C8BFBF
+05A259BD655B2AEE4BA2DD04935BE78AA36151A76D3DEC7B16BEB5C7439FA66C
+D18F0EA8B0FD1FDBB2C7718C6D6F60B8B26FE85C808D109C9E4F62DCE099D218
+9CEECA5985E6A930F8A78DC2BFB09CFADE3EE6EE1A71C735DAEC2EB01FAD7C81
+71CBF28E6D4459CBE917D87B80D6ECD20FADE383146A4E75A5AA65E1A8E60AD3
+51E91BF11B524E39C2727A6C0D355F44C913C4DB4243D07532966D5C4D364BB4
+543CD6929DA2B626048DA05A1B7843A4544F855ED61804D0317AF029BAFD2AB4
+876B1513CE3D795808FA0BD050E2DB4630BCF0A3F2AECCC5CCD584B955279170
+8C7F30532110312D0CA374E53E63F68545B7EAD07EC04F1C75539E850E649779
+6F0B5278F1BE0979BA2B969FAC22F6811E0B9133FCFF0CECCADDA634296DE080
+F693EA18A2461D9422E2823C51ABFF572D332909F1752C6312A57ACE6CCCD9FA
+17411A598F7E830984DCAE07AC4BB0229D60AA03B0A4D874FED1A864377D6EC3
+6F5B70E2FE39A0EE4B2E8DCC3056216DE2415F6725D54C15C8B2B7B3E4E3E3A7
+6F9E42CFB7FB5CF8AFAFAF8A3FDA4DF46C04EA9AA8F36E1848509F0850B6D221
+6F31A27F335334E79BD776A88B1DFF7CD00EC614CBBD6E53A889A32BBD9111E5
+C7342C9F425147907E55FD1F15E723571952DE7655D43505E38F10BFC81DFE36
+1C62330FF3CDF15E345A089C369E40730AC7A716F79218AB308B12FA82717EBA
+693FD49A020D7BC6E19A7FFAA773A9A91BA436579B72D7ECEAB4665F2D00396E
+C14BB34699D454AFB879A61380308618855B5502B3EE358BA7AF8F8C7C793DBD
+90BC9F4086E996CC98ED5AF7905E46F2B331E1FA496DE6EE4C3805EF90045364
+D9CC995CF2A903A07A05D95F3A070D863962F45B62C911A530A4EF67407F41F9
+4E6AFFC26C752A841FF5057E6D855F120D9D28F5886DE77A2D300A70BF15EF6F
+6A5FBCED92F9A01800668B37141405B50D2361A5DDB12537032C000140BB4F55
+40239833345D9A6536CC04D9BBA6F2D3172347E5B9D763553F5F5219E20D3122
+4069388532E29926355F1CB6644713F864B2B62D7611657E1FB52A8E7B4178B3
+766FAFE9CAB2F1BFC41BD2AD1AAA8F44D51C843C75FC23BC48860B04F2C752E8
+BB379C86980ECE56FC5712E98C7C2E7870EB1E878F5D72B1C620A6B46629799D
+B341ED8D9E6B830336C4E690626849E1CFFD66DDB2DAC99DB493A5DF24BA7DE1
+C1C88AABBC6AD77E5240B37E42C1F76C640D9554C2A7AD7C214FF2AD422016DB
+035CB47A085F195A5EC0D456AE3AFCE12FBBB1487F1A9FC289FC856A855F3B79
+3967F8FBF57C5F5C540D6DF14371B140C0DF167143684CEDF0596F661F3C1E5E
+69AB7A3282D918A9DC6165F1D2F04937ACEAD13F50A11485445567C5BDAAFE0F
+F00891D2389171D7A62B631FE53A50FE55262B70B2B5E267996316FA2D89B094
+95F0C36181E2BA08180C7DA957C7ADA62B2BDA2F175F620DA7474138B19B691C
+2ABD0B87EC5983F28A53B4E1602F656DBDA57484E58FA00E3E1113CAC39A46A8
+D323A4EF0BD4C397C814A148EA3F6BFAA1F1AEFD89FFFC3C0D4CC652A6EED5D2
+0250E59F13B2963996B23F5A202BAB3804F861050A1A68352273B5FC03AA6C98
+A02B4E1A77351A3D22DAB1B863B1CB8EC6A7C30857C661CE7866516D3D4D423C
+83B9DB0960FEE729D01F1350932304804E1760CA4318AA8C4172C11A1E370E41
+F0553D4CD81A4009385BD900C7281597795AC3E1588955552935ADB5945333AA
+AD58E9664E6CC32BB2E00EFF6C495285B079F4C43D3A4C522A7ACB09EAB4B414
+DAACD32F9FEFB5500B60CEB1A36B865849DD999A42CA0BA0FA143CB5E2526195
+4081072B5519457C5292DE0C9EAB3334CD0B4FE28EB5FA9EEF554DEE92EB4EE9
+54531661F4F89E620A928587ABB62D3E5487AFF152FADF2FA795AB4A15B064F6
+D12F241997234C85504DBBBC087E7D78C3A1D76670AEE02A359ABB380CB660C4
+2282A5151A26D912C47EE8DD6C17F77755A668FC07AD983F14DCE16EC1AAFDCA
+14C0A35FC2696DD3639D5465EDCD6141422E98AD6B62337D746DE9AF1396B52E
+7A8AE4DAED9A4F7857A8E536AB6902E1C641967570D4272181F25B428CACCE8B
+386CB4FD821DBCFA2DFE97D7A16648D6D2256ACF48752B6E4CA82164B1BC574F
+171C814D8684206A07976818A428872B24010876B9D491DDD8202B87999D1634
+53ABAA96B7C04D089ECFD3124ED13EC092BEAF8600D4E2FFA48F494A72144BC8
+B26A5CA15776034BCC26026476E62C27DA349F822194E48C42B76195FE81E4A5
+0CB66E8E5E63AB49814B854A1AA3B6488A543AB56152BD814313290DFC3D55B7
+33E61EA591430BE394B95B1C9BC783135394EF1983CA53467E8A32B5D8538655
+365FD7E9B01C77CDCD033A71FD8D122674820BD3A4BA0675CE5C977EA21B08BC
+C2F7C1F95D83B43C523C00E66AF5DB996DA1B73CD07DA13B686186DE3292DB9E
+663EE1C7A30D6805A678A5B312F9232C934D63F563042C4C7F4C5C4B5CD21E1A
+B4474AFC32B431E4D0990378803221116D1C86049F297CAD0DC4E12D0FBDF3B5
+F799FBED0BBE17872DE2CB6C0EF8DD486A29F1993DE0ACB7AF4B7AD9C2A85A69
+1225142F2539C2B2AED28766FE59B80CDA8797210B455C33099CB57AB5FA7FED
+1C31D97684EC4AFCCB4C4D60C4F7DB9D865685FDA1E76FF6A5DFB4108D0FC241
+B12B498763CA32F80D6F409BD43905403651A9ED8E96AF0BE8CB1CC8820532AA
+C1546708749FCECD26C5D2A945BAD576F05FEDBF218C6B31141591E19DF929B0
+96859553E674BF96790551776BE307FAD2DB22777C96B9A9C79990BC6E3AD6BC
+7C20FFF0B0FDBDEC1975AF03BF403D9103C602243A075744BFFFFC2024DF2C20
+BB3D29F6DC452EF438AB28077E811EC9EB5D754446CFA84AEDB7DA8EBF4BD9A0
+3646589848D03478BAD908E2D4C57DDCB79A4FBD1AB25E6252329E0080AB0D19
+D4A46BA8FBCCDA054202DD292B72C1FCCCAF1DF3D4F4C876B90FF0F8D561F258
+4FCF9DF03CA5AE7CB73F693D2823D2330C5045F3DB1177FCF6C942D283A35641
+78B16DC23E77FBD518B7350267B9586048EFAF77ACC9EB7C997184743AFEBDA2
+F256FA18702A7183A71D155FD8830DDDE49B6F87458F529C89BD1E945EBF1DA7
+1EFDE6B4CF75057ADF17D27DB378976546C566710D03B2961B50FFEF8BB1BFF4
+C05788E35E770F8F6C949F611DA80180414F772E69338BFA2C91F6C2145A706E
+32005A67C14E81AEDDCC608D976DC9D48D965DDF9A9E49FC698B6978DE5A8272
+4EBDBD28D88F2E6213C5CCB8DE3C41C83D38DE92355914111692A23B79EB6DDD
+E77E007AFDA2E05A25899E4DCB623000FE379C01287643A4CAE92766333023C9
+3421919877F8560496B5358A059205B6B6D1BC4583D5AFF288596F5147F10063
+A06FA6B05B7DB4586975C91F0056E5FF02B91FFB592EE7F0DF7D9550C6803A75
+8D67460C8B03D77307B8E78302B763ECE3B6C4FE27B67AC8457E2F8DF4D200D3
+9B16611B64E2CD331B8F305CC4A2539C505E59D74CCB52A0377DFB314E742818
+AFD337E5D63451CC1977C27812F2769CC962EBDE87872EB976B10F0FA39ABC9A
+571E179A2E483F6195EFD04C67D8F901513945D7768398D5D7478E0897B11DDB
+1EC1E2CF588003F5B607398D8D1D9A72D5E6BA532E88CC0465B8A360801932C6
+8F369F408FB349941BB008B44BAFF709F68F9E2449889E1584A5D2060C337BA7
+AA37BDB8E5F2BD43FED0FB1872DFFDD3C31DEF34450FB51BB82105805C42D8A3
+1F4BBA3D13D7F54B830C4E5F4E273DE222E42AE811CC33458D7B7FE64E4C9737
+47DDF60CB4D69373762FBABF14C823A4AB38C84869C25B5467A427FC6DEEAFA4
+A71F39A4395D774818C0CE55938B9964074E74D6269D08A53AEDE785D4534604
+DF78B7FB9508ED6496BA8ACE6B300818BD98F8F608CC2B5F059999E39EA90DE3
+800A785BBAEE0321A82AE8B961FDA35E7847324546E90FCF4AB8D8E8DAAC0D0D
+B097D610511BF1397B0092EE04A4FC63B3780AE89F9985D8A88AE771480E2954
+EDA2E11E90EBCFFCAF67AD39F4B30A07883424B87D8173167F7BD687BD56868E
+874466ECD90952640A5500FB8A6D9B0CBB4CB8D3D8D024BBB350E280D9E7C030
+8F696EC68212BFB9F011D4D488047C2C1CC1148BD12D42DCC1502544EC1FFF1C
+800718511EE52FD767C7D0A22B029F4FF65C793106B074534B6D1BCBBB3B2C3C
+7549844A1B650C8C75841A60715BD200FDC87E307E8560BAE1FC4F0847F3FE75
+AE58F0A450A58359B833BB2294DBE5F4280E25432C75423A8C2DFD44FEE88B48
+462F09E1A2B6C70C18EB90365B83490E7A04019E9EEB5A8C5E58B3A01C8FD097
+BBC859B0A1C8242A7C2B82CD807742109F11DAD2CB5647C63C81F851C2B14795
+E0CEDE0ABDE6707B642C1C4B1F20791571DEC7224C649004575C3E24C6EAAD76
+20CFEDC819AC43646193ACAA5B63B7AF7B1A9729332E52964A987DE0C0D2FA79
+1A96D1EF7BE3B5128FFDB1CCB99CF807D8FD4988E2E500A8C46E2ABA59CC2A7E
+801EF8542FEBB42201D4902E6C048D9A4AD5B6E94C12973A84FB9B3EEC507EB2
+06EC66901F9D6611C8F8CA1799DB484DD6F5BEE0EEE8FB1C3CC126177773759B
+2111037691278483BED2535C9CDFF72F7E021FF9D8B3B1A0C551996EE303BE7D
+5C46941EB329CA3C9B697502A6AC8A31828594C245B97DD5ADFE11CE9EA8D0C7
+9C8CEF26DC2E0BA66448A48C14AB1847DAC1B280A45CDBB22566F4BFA55DAFFD
+2A690EE0E3945B3E1A681D567442F9C97E69DF75E02226FEB227DDC03AC61325
+BD610D5AA573FF089B750EA0CE8A40F85CCE600870DF84F8C62B929A87BC6E05
+606D135A4964617A3CCABF68DA95C06945370A99A717B01F58E015E37E61618E
+AC70989C4F9AC115144394ABCEEA424A92EBC1E7EFD8A192CF4F0A10AA6E46F6
+EC1B6C43B0A775B10B0FEAAE02BFAE9C6DB22C3E962F1B5C7973CA9ACE819DCB
+049FF86A25A8E82AC985F5F5292EC815FE136DDA92F925E2CE07DF5FB7676E7B
+4C69FB443DF2EE5B66E740D4FC512AA688638CA3B3FFA24A33523D8363E9B70C
+F10A460A87CAD9CFE89A387A4452EA7330FAD5DEFA019C6C8ABC8A125EC2809A
+555BF63067F8883CE40A5F1FABF7E3C9E851C097401CE2AC81070D11B0898349
+030C9E0870B2660EC8FF9432F8189940CC98EB41E462675E7FB51FB3FD4170D0
+7082D61DE12AC74AFFF649981F54AEC4E19F5EA6AEEFD49F64DCA9EDC4BE766A
+6D10E707F824817F9719696682A365FCF6AD757C3C9E49600F7A545B1762E062
+1A68204E542F97FA1175E3C783CBD94E04FC9940BEB21C5D44FB8D54DAD2BA1A
+DE36763C370B130AE75B1775CD356D07B0D62195BC5590B27216DCA74DD58B8C
+E54623200578CE733126174E81064C8D23AD976E3E8852ABCED7DB7AAC1FE718
+A8F21683BA14A3631982AC240B4928C144F8D85D1CAF20FF1CDC26D7C5862E99
+E8E95F5A718140D07684F7C64B985C8A09A46925C63256D6FD52B9B8B281949C
+0E80954D268ACD63CC83771DCDF145DCE797FCC032C3DE1C800BBCF7888C47DA
+74CA25D3728E656B6D8FD74D49EB9A6D7DACB2248A246E8E554D8557F5D3D084
+B324123B3B73D8ABBAF1723B65B1245D66F0BAB39178B78AD9AFC0B5FDC30F79
+B93E93D6866C2C25061D715F9A76E0738E34D4BF913B7E4F32673767AE33C2D9
+4A40BB55AAC77651BB765285CFBF741D107CA559BD7584E0E0550E7CE08FE176
+46A41DD674DC5FA4580A3DA9C240312F90D0FC594B983C3FADA4FFDA483F75B1
+1609CB77FB02D446F1059457FCE06B8A5CA3EC0EE3C0BE1F5AE441625A31C835
+79AD3A0E560B3A37721A8A6BD55BDB82ABECA2F242D59A902297BC968FD5BBFC
+F9C26D07A6B9EBFB3E9D1604FD7B959DBDE994CFD70E765C5106C7DE7F413F98
+90BBCB666FE4EAD6ACEB2CAE3A412F0287B44088C24E97CFAB96E18FCEA499D9
+890AD04C419774DF3683D95CC3A67EFFDC717D9094E247AA250DCB6C54BDDEDF
+B4FB572A0B8D49790D5DC10F75DE1421149EECD00177AF315A2CEB014DAA9ABD
+F117C29C4A029C66D8076AF44D24B4FAC9167C2BD692DA0D53D4C551F69B1E16
+60C6709D70E11544C2322989E83EEDE0F7B23654CCF2E2BE5571F9DC1F97FEDA
+3766D62D8DD76D51F8FF9A2C95FA97D72C36F35A4D9B9E1F10FF1451B8A45937
+9C07B6651A171F259F5932457EFE5FA6A760696F56A4135E9947F36557B3FC24
+4C5F534C8FEA30F2F8AC526E5F69C12C2972FBB448E79CD3E2F326EEA2E796A4
+0635A5DB40D18E4095F7DD966C71B9A60A322AD0DB0A2A9AF24BF04B08224ADA
+32E394F0165EC9752E7395EF268755888FB73572B1B74A60C7305DAAFDD9F281
+11425CBE9D25DE6573AB27EF3099D51A85DF5EF4C9BE135FA380E945A8D32E35
+3F37E378AC231C48F01BE161A1532FADC9A9AEE85C457EF6BA291DA53EE915A4
+208A681520E770D04CBD5EB0159711A141BED8C410583689BB5760FF00385D89
+656753137F77FAE1ACF3AD77A13EB3136B7F1A16D9D5C33648CCDE23704C4F87
+ADE05DF8CA690B95D66EBDD3F6D05494BB6CB7E67AB22418124E2C8F512B64E7
+07FEA1132401AC327C3413B36B36433C2F40BCB656EB15DCD30BD886CFC46745
+E13F83C491B125848620FADDB360F1CC30F25BA7CE242ED619F8F385898567BF
+EF84D301D215E4D508B50A25D4AC9343C947A8BEC153F9470B5B6AA29D2C0391
+535B58F6ACEABA8B5C3B622F992498341C1CF3309FD79C181515F015F46615ED
+2F2C1FCAAB740C411DF3F0FCB4EDD2ED62C5EE15BBA256C1E95165A1420E70CA
+06B1E41773201B36262DB83A2836BCA7E957ADC940579A916EBECDFA7A677375
+18BA68A70882BACDBF795B95684DF840906409FA57EBA076BFBF1828505C1245
+0AD3B405E2DB8F45C11F9183D58A08570638D95F746DD4849961CDB3D48447C6
+B8023594D21007D5CD223602212F6D8DF8A41540AE32949CDCAD1B27A798E25D
+8DDC05BD296F8229AA69FA8B9460D2C2F5630E77EFA90A212DD6910A5B855E02
+86893291441DD506C58CD89927417B077890DC1FF3ADDD4CED8EA9F1BA0EAF98
+873BC628A7AD36349549A217E452D3368E8530795BB77F1E756FCDE2040C5F9E
+DCA72CD0D807CA1FD7B607C53B5FED45CCA47DAEDC6927600C1315D2C57D0DCA
+6CE850A080CA0B2530D8B33D1424B884BCE550B6AA8BA4EFE6A65656D1C02547
+454E34A790CFC21D3BA6965DFD0B87DF98DDF41D15E5856A3AC663B9369D611A
+E2ED221BB8731D2090E2DFAD0CC282903636766D86CE859601DCFAF54662E280
+8347A3FDB3B37F0FE340606EEE2B8E7C93B41C2DE4E845C9952347A8D1A0F194
+4B7E637C48BF2A479844E7BDABA3261EA98B159DB0BED746910D4785ED3287C1
+0F46EFDB4C813E895C5C60B111D2343793F673C57FA42DA5CB401FA1682CE5C3
+4AA9E05901B57004078742A8CCBA353AE845716CF0D5ABA5C255C90408D322D9
+F21F14DCFC28639AF0A884A38C93A2B54402A7161B059608F8A10DE341A684CE
+6D225C8A715014413B07104C029F63C8B2A788FA68E6DCA985CE5186EF75C806
+10A23B0B39FDB386CB0B5B1FA847972B79E0645B878F211EEA2A14B4F245C319
+DFD827702307C47117AB2AF7FB207354DE283352C29010241B4F57890314C0FC
+9FF918034F77D93F2EECABBE5EE2F421261FA34EF7B40E955EEE55ABA18CD355
+27A99A522FCFBD1D9BEF3BF40C7BA74CAF58ACDD01148345D4E109D6336FABD7
+4BE82B89759A486687EF3D8735422708FE0F80DD1034CA9740B85CEA71A2D9D0
+D0084CDBFDC99E0219A18C69BEFD1DCFFF6B5D97263D1A331AE0DA2A56A4C5D3
+FBAC1DB7289A34157D25A8C41FDA4C3A66BFBE90EA5F6371E94D69427FA0016E
+C2E9DC906DBE094A05B35546F28B5DD2BB668AF85F96D00A5556A6DD51E5FD54
+F7F77B6BD39FE1A99FC26B0085E1EDD50912E1F1585DE9C7233942B0AC4E2504
+F5841A727459F80434CEDDD3CF5156B36BE6F4B09AAAECF546B1F6CED3601D94
+28EA6E3EF0456C7398A78380214BA07B7F73091BA85969B07F4EA13F2B294B40
+56F684D834681053266D8466ED3EDAB77E4F93A5BA9F32D8D4DAA968B4C41EDD
+317284A980A3ABDE9FC7F153C8BC5C073A47D2BF75B2F724E90E520123A413F7
+80B4CF9BFE0C5BB596331D7E39505582AB6519E34EED28A009B66F8CFAD3E204
+81D12C62A5FDC8DA03D1F8E5301DC6894C4CBD3CEBAAC76CEDB31566FD7545F6
+6A68D2441AB9AB9BD353B51DCEED28DBC90352ABA3D249A05C00C299928AE6E8
+886E8A5DC68D75B642E78D8E16A1B8BBF871381516D1835421533A49FE4EA891
+512FE6949FBBE31256DF1348C3EAE50FC45A865E5725F1ED7D5F50D2A5EF1C1F
+5D0E4E86E362C7060D8A3DB71D46B224D5B5868F34084BD408C7EECA270DCBA2
+DB170405493E82AD7E8B31708EF61421EC37DCA5871E39D7FA29E43F6FA45DB4
+68C07CDE5F7549E07A185B095453346351D974462340F64FF04EE1C037871B81
+FC1E8B6BA4F6CB9E486B8A7DB086A59FA4AFE5C74460F08A9163EA3ACD1380FC
+A7AF2CA22D2D4CF17FF9870E206CFFD0C5CB90BC4626C74B983536EA9E31F0BB
+7B3E9AB8FEC135687C0C1B69AD5134C6CD428DFB9FC8C56829F9D828693DD3AC
+9FD5C72378B33696BA7BBE392CE047E06114DE1CD7C9AC966013C65514EB2D60
+6349F094D44C1D248F4BA48DA7C3B8ADBFF14DCEED6B1E8C704464A7045E467F
+5E3A7756E2B7971332DE09A2178F46323B8D3C3904FC2814E3E2A21D8BEC6CD6
+C5383201CBE12ECA055417675F8BA96C4E9A799679743E5D012DA2B570CCB7B9
+0BD0520CB34297F64F93B674B7A5D2116B2138B75E7DA175F75F7139296537B0
+1D9595B65CA7AF585CEBE5B5DE485854D9F67DC07D0F6091D98EAF57EC3F8656
+ADEE982416918DAB7B6B7F611F7DF87C9C77755611E91A0A309F05961FD6A43F
+4DB6F0714BB448A20DC223DF13CC87DF53220A292F64285A12C8FD0AC7E3D962
+7BBA836968A2EC6BB70B5667A1DD8E218696E105998434E7CD32D31235E0B44F
+7A7D65A8FD4D2846F0E36DE450160B7FF81C63C2310372B91DE5D10DF21CE43D
+E9D8C3911F0AD72D28110E3D27B71B531FBB6FCF9C1A9B91F84AAF4DFCB2631D
+3C2B53E79AB919D5D99BA18B2614A0C8B2D161BB42795B06E53CE266EAEC37A4
+B562A6B036B397227D35AFF001CDAC7107DA54B1CE20DB7624E0EEC86A02EDB2
+B2A5B84018DDD021D05B28C4BB97306C73473CA4C28C8AF6BF2CE161D0E6DE5D
+F6F249335C2E34FAA98420B7D8189A00F20910BC96626BA663F4B571B565EEE3
+9A8CAB423E3E17A3F95DFD08F690363986129799E2DC1E7289C50DD3651BA8E2
+F53689FFC4B02C015F34CFA75555FE47E644F44CE9BCFDCC29DCE7E7DC7208B5
+CC3404C23D893B343E7291A10909F9B5FE3D25AD1FB79E82F837DB3AF819792B
+4617085B18A6B217954AE93730AEA3FF8D6C6E5579529C02D6DD393AE864285C
+1C8E4F8BBB5E958A030B897C43754839029BA98C735A65C55933A0C7983AD8DB
+D3B012BB2FD73038960FE1B9E350FAF7E3471288665F360383A15D95350B174C
+288E5B4A2F1ACEDB40505A1838444BC3ECBE6B1168B1F7387BAE186C97A06208
+B3A1A738CFEFFA3F65AB9F79B8C8AFC39438B5801BA60DD8C3F2742D902FBF1C
+A8074228728D9D58F7FC064EFA50047B7A1C6C88459E0291636F4301E3036309
+78DDF621FA5792483CF8A16306759C464ECBD54421EBB846895DD87183DEA62E
+68273455B5FCD7FC6422C8197DEFDCE70F9C115CA0C91D3C77F7C9C36E830047
+7590DE3316BE60FB421E6117D2F8672142805A013FAB0466C2CABAA7D16E972F
+D1AD0B8BA1F55CCC039B54050160724ECACC8408AD8C51C9BFC2E9268C110A3F
+FEC30ABA268CA1FC27F64EF99DD11524AFFD45A8AE403B825A08692DE234AEEF
+26AFBD9E79441D77B945FCDC5A431214D4A96BD49BD129C158110A6E2BC07A86
+E32E552BD34F1AE95A393491783771115DDC38979BC54A63F3E3FFCF033990AE
+4A9DD1A72CDC770805906CA92828EAA19D03A0EBCABE364A22F890F594068825
+EA2E6E3040314066813ADED10C18A2A9B0BE5CAA131B690EEA54DA92A25E9B5F
+2A2781FBD1BB43DDDFB3FEB28BD448D0E2C799A063A72E9BF3850E2B418BFA5C
+8B3A81EE6A2457AACBC6CFF8AC361816C238259E3F58B85FB88B1E36AD752D13
+5CF751ABDA364A09648DCA8E213C1AC42190D511CC94F2C1BB6481DC1EAAF88D
+90ADA407872803CE33AFEC63DFD75BF25D8ED8521BA47B4D434891C5FE4C2659
+9AA517D3D5AC7FDE576BB42B2DAD5280D64764AE205A33BC84EAFFAF69AEFCB1
+188BA530C45B2BF97BCE61638429ABC6391D95A8B04006F4B01D8D01A4718976
+005A5EEF09DC4DE93298F0CC4FDDB8C110C3F3D9BB84626777CFEB7EB1AC1C36
+156D7F2B251DA2F0EACC39AE291919B427A075FE6C6A65A4A3836C3D459A9252
+99014F5E7033339393E500D28B832EFDA4B0A9850AB252B3C9EE7ACB3B4CA00A
+5598F2609D5625944F7ACD52C51FEC9F64D6F32E38E3BC252BE7AD555D016EA9
+28E77FA9D7C73988C580EA283F82E5297F2F6798AF229B24C8E72F1D1AD0D18A
+C09E78E299A4C09C978B4898D7680FC3AB917E6CFEC4911225B2EAA9A116F15F
+392FE72F3E1AF52C67A0DD488B2443844AFA127E78E92416ED5A72D61E92B9C4
+F604C63A69CD33237108D1EC3D62CE43404FDA456542C1C21CF0C0646D67F879
+1B1D53BE8D243862C3A86B9F3AA44D327BC5FEDCFDA066153B87EE4FF6F177FC
+39711E874CBF31A5984E971F86240F7F4A60C2C81A07E972D7DBD34204F0653D
+DA8DC7284A4CBDB19BC6A1CB75E9786568144833682DE7E107D639DE7B293E0E
+F08F418C970FEA42075F93C77FAED3DE64B1FD30564937013D36F7980139F968
+06D02F6481577A41414FF4FC9B1C99AAD2B3E9013F6AE7E96F782F3FAB4FB272
+FCC783CA282B79E88608409BBF8AA3DCFAEE4AA0A4F4E143D8D62175D2CC25EF
+21CC2E6F0EFAFAE0BE6BE6583B624F35994BB75A886883C4429A154E15315068
+22CEA98F0E9346E1FB0A5C0BC2F5F08547F366367C6AEAF0FA2171FBCDE51EB6
+DC13D8E07798020CF02AE39E860B1E7B5A957214F2E88FB51615FF10CB0FDBDC
+4DD3F7E32E4B7F3ED59A15F279C678ACD0DF52FB6A376453124FB9E911941496
+A1C95943D464B633EC8F8003182D4E3705D4C3C12D2D8A6D2E85EBFC38507CEA
+4CBBC55843A9687E012894D9486F76EC3455B92702BE56E68B47AB3EAE17FE59
+83789C8714CF93C38AE2D10F71EAE95E275A007073B4495329DF0E6F625FEF0C
+8FE78B98F219D7428EAA2BE973612F80A0EF2577FAF84CD3D33CCC9B8C9E2E46
+1A3884A6D69A044DA7AC615E7756880D9F91ECF9CF24F64F15AD989CF31AA443
+8AE71ED33BABE92A2CEB2EE12037AEEC7DFEDB8ADB45ABC1E85BB021153F4977
+DC71F5C38099B9D7AA63D8569FE519B523843FB8241F80113C6498ECE38D92A8
+5199F8A0BDA219D9CD946D41E0BCA398B63442FBDF3548C7B0F46AD4DABF54FB
+D0B0835EA5341476510BF67481C40FF5CDC918A128AAE12C8F0D02B1F058A283
+7E5A09279F8B9E0F0E0549386C3C6DABDB173D30E9D3B07EDE6A7D406CFAE95C
+AE2FF542AB24BF4E96CB7097C38A5DD350FE9FED91CD5F6316B64BEB6D4AD015
+DB75B25AB2280FA089FED6A5CB57A24E404CC12951B2746345977A58CD25C32D
+FF9474A3EB149536C07620C74122F5F54FE24735B35A34478A5D721F15C1BB43
+BD57FB09175F2F24997BED9DF769507F0BB9B87D8396C8CED5DBD4F175789AA2
+511FF8E569F3F2DBF7C0EEDBD447E20EBB09ED273DF7632720672C19204D9813
+C965B05D0C11EEADD78B291A5D8F3CE48302BB4DEEC92C5D679F1D23696F4832
+A0064CF3462EC8D6AC28980641DCB2681ECE09EF60A62BA321260BAF201FEC58
+CCFB371B9041BB950AE000B329E877A54B4B83F52E98D26C531556D53E0806B2
+37CC3AE746B108D927DBC45ED2123D46BC46E0772810A4EE3E8FC8809372493C
+22D7991EB737BF28C6D7887F74D344A26E79F6D1156952A377B9AC0B66211173
+7AABE45A309A546406ABDBFA7431E1CCBDF11214F77D10D352B54CE23B14D88A
+688CEBAA621A014EFD89D5B905D39CD2BD85D6804141A58A2C38E861963CFF5D
+C7BB188E879A541A302C3A4D99BF2B1778398ACE1DC335BAFD7D7643DACB1E3B
+781BE43BFCBA8BBEC6BF280F76DB418D4FBE3C36A2F9ECDEAC32E3602B01D7EC
+47CBF2427EFD8EBB5E4F7CC16884A67C8ACEDFD3397CA8C2943FB0F5050DE719
+5F45D15DB1AF12BEC29ED5DA5A987B384D2EC7B432C6BDB3F6D22D4A4FECCA71
+CD1ABA35626C274AF44F748DD9DA3763E6E1BD19A7C07822DA6211193DBB375E
+AEE59CD426FC9F42D569E75164AEAAE43D2940E18BE46C23FE5722F51D4F42A4
+1F560EF7A01B4F2EBBF2A61FAEE03CFA912E644A7BC7BEEBC5724415BA43C322
+70705C5159EDF059AC6CF2DC896EBC3F35C3DD5A29DB44CB86E4F6BE9670AF74
+6319337435A00688940B3C24475870D2F46F91379E5F3CEEF23073E44C02BC51
+905FFB8E529521DA74FC123C31F4745999BF51D38B0AA7CAF9C169455CDD05AB
+0913159BB7E28F6D0106B50E32CCD0340A2E41B2C66ED74DD370AB5E0EB5B0CB
+93A07EB9182ECC683E6503832680CF2914D054D3BB768A3F0E3693F5402B120F
+C0941273A0E3D6E620A90B94E186097965E5B2EA44D0F8CE8CF0CF290AD96228
+A26E6CA3CDD35B919FAE5798E55493640EDEB67FACBEE713A0EE055D9A18C3EB
+9D90E7869E36B749F58C0B5AE89DA856DEA4122B05A35A863FB6BB74AFAAA182
+052AB4D8F033F9F800200B547F736D32018BB4B64157D12C8268FB2C6E9C60ED
+C3902382BAF7E12A562048E9B28563E70D4A52121B40AC2171592A710A9EA19D
+1A0FA11A0E9A6FCE9FD2BCD8CA488F65B45EBD61F17EB8C6213B3077B6A9295F
+B184234F6B37C4760BEDFE16A31CDEB901480A556186CDA8F4A623F8352E29AB
+9FC29DA356817866C11AB07202AB6C2034D8E463E026CF59FEC872BEB71E64DB
+0A79022780C38ED86FC17A2EB552E9D6C23C55F205A05E4E198F560F7C1A277B
+3B4EFA96655F8A5E9D8E7E257EE59C734445E864598A74B7F6400E05EB0264FD
+DC3AF61560ACAF131DD490B2FE9DA7DC956182B5CDCC177F3CB48FB6E7D8D47F
+F984C53A1104D657BDC7723E995FF55B87FEC6A0DF25D87987BBEBFFFDD9E6AC
+A945B06553668DDEF15CB7298E4BE637FAD0AF624171EF49345464A266CF2BE1
+544588BAC063DACDD4691111ED9C754A4E0D8AE88AD4DD3100DB9C0C9E1BA676
+61AC53AB391E9C9BCD240C9A9D565DB67D0169B90C629CD46600687E93A544F2
+0A67B9E084D40B657F259F1C500D7D05CE3F059DB9084B8C9B492C4908E38199
+9F6E1E625D7FC73505B47D4335A7ABDDA2F196C1AE0C41870B7A38C09644641E
+6EE2686B487D9CE20239EBF677CFDF215190EE0A1CB439A13AA4CEAD30A4FB31
+25B9039B7AFEA7345D3DD1F321B61D4D52FD3ED5642F98DB54A848F838E340E1
+0490E93101C49B734294D14E714ED2A7B0CD79CEC04AE6B69EC188C252B98E00
+DECF96DAF3A8614294968F426CA0F5DD945EFEE6449E2EBBDF124452AD854E3E
+B58FFCF836944A34B90540073A745658B426CF444B36F335DC2CDC9866F906CB
+E4CDA4A7A3334D764CB27B2B4CDF8EF5F466ED44DD6C6CFF642F252B24A267B8
+B8788E1272EB5DE03CDD7D02ABDEDCD22A18441DBDDFC77284E88AE70E1521F4
+7C49CEC8C25BEA8EF8C160B9A6C75E8B12D9DDC391E60CF7D6CF02EECD7630DD
+24393C4DA80B1F3EB35CFCCEE03675514A9E110946E65B123E19427D8FFE99D4
+19E440CCA4BD1834CBBA0178F9C98BC97F5C7FE1DB69DA5946B0464E9E333E75
+8F0E46DDD9D7BC7A8939463AF2EE83B387F14A3CF49F80F62BF8667E23F702B0
+3E6F507420BF6EB2C5C37BA7B24332BE2A34F3274184F544311BD53ED0560BBC
+3991A25AD90C14181A274F84CA7DD21741167F2B38A54C80B61DD740A4F6384D
+42695C64DE34E0073E390550599C26B6DCB8557D09C1287CB90575993AF500E4
+CD3F8EAB3B908A3EF3D49B0DDCE08490BCFDAA4CA491F7EB9177400487C58FC2
+1EA33E22D11600F2E752738BE59936B8E911BD8820D4F7F687667B32CE884EA3
+7569A82B0C53A3213848D6C973B9C3293FF022491E40F0A5BEFA80DB18531FC6
+7CB7A19B7A7E46AB761618BE20FC4742E7BE854071C3F7BB7F6F23DA29B0FC27
+9348A6E9D29B8949C1085AE229902A95A672DB5410DD239A4DE9B2A7B2A499D8
+4B3D82EAF8A8BE17151086314C9F07BBF1E0443BC59F82126658057BED615C69
+7D23057253F8561D11C6270BE79912E6240BA5E6DB8CD7D7E86103BF5068DB42
+6D1F769CBBF97DFF3BC3F5F0E64F133D0F3D4DBBC55B7EA5641F0D8F2F7B7467
+7F1211238EC7062C69951E0A25A77A7E7FA45660182BCB1B0EC3950735C1C539
+708A37BE3B4D617FC2D7C4D5BED4E1103D70923AD70FB028E23C11046DD5141D
+CE3BB80A706F2D66068A8B8CDAF22CBE1CE71925825A10829193B8F1C6F5675B
+5311B57E876E70CDD11D1212DE8833C5F44E07701C7E2E63605AEF8BD30F81C1
+1B88B6EDCB47B6DCDF3E466FEC04680A83250145C0ADFF58CED2EF0006371568
+854831945C23BE79C2655E512C967DD3924EA56B8F99368F32379924FFE75680
+C8C31A75B2733359DA01FEA8634B5396A3AD53601FEB7B897BF927812A2F5614
+7C65D725DD636C20EA6E69F3214D37E461605D6C42C024F69201C8BF91B3BE00
+75D73471A2A6BC927F2F91A183AEBC0CA04A2ABF291A0F10DE90EBD6C34EAB53
+F31F148FC4EFB7C68AAA772414D9C114088476B504886D3FDBBB664E56536621
+639060388A3E98431C06F9CED067AB46695486E2C88F2BDF55D7ACC588EB7F49
+02630F2A0852C8243B9D2ECB518BC69C547764D612A60EEAD68F3C06AD2E221B
+CA8C4F56FC8ED071C5F074F90809A344F58D01CB89CC467BB90F4C400D11E515
+032D783C341BEDD3B1C08125196731805033B3769DBA1A62478E0224FD81C7A4
+0458E97E0E4620371EF311E740825B3A499A1C2FEEB4CB0644526E66FABA78E1
+AB93208CB5BF6E78D32331F55DC98C11A1F56592CF133BD05C8E4AF0AB80F1B4
+BA021BE93BA047B7EEDD39EF35441D2EE71F0CEADE691DBD0077A34AAA5BA616
+69410DD5A4D71DBD12EE5981C06A14CCE062ECFAC63C37DF155F9D5E7BFED397
+E0B51DBAECA7347F70E7B68157B0D2615C661F5F791C9439A934EB2C60C53EF9
+9A300F2531FE810C143DE75C50222CF7A540A9F2E443BC5474A80FF59339E6A9
+E90C6386C7B54A266FCE858121DA7F4BF33D46844E0A8CB60A002B204AEFCC42
+2410ECA4EA45869CA0956607156FE879ECA490A6E839FB735E20F11FDBC24CAE
+B300F6771E7DCBCEFB3AC249E0B521946438E56FEF6050289B40A9B3FDDB659D
+721704D110DE1FABB9851A703B34ACD49516B00C44EB17C30A8BE7CA8442FFE4
+3FDB259233CC0468E9F3548D4086A955CC1854B9D12D42E799659BA8381BDD7D
+FA07D1F08701D584701AD888F86D86D7F11A1AAA21A92CE24C125CEA937C3C4C
+923422498D766E050E0E75AFAD1DBCC9CF3B812FAA5C9CCD2326FB8A0C171FE9
+1637A15145FFD0A10085BBD051A92E5625817CB6DFC30880604BA6E124F4DD80
+2DE36A68F0C5D015B8E58B5EF991DD9D41FD823BE3652515A75959F5A991C5E5
+BA8E0649E15F231ED5C5B02E2EE1B5A478DE7DFDFFE1A604F3AA191B6A03ED1C
+7AC466B8B0BAC7154165273202DAB004F72CCB18192EA9AE584F1F19DB8DF12D
+5A6D9BED63F0E1155ED35B92A262D8851BE35570F5FA295AD30B28585F680306
+0791BA62FB631F7CBC850FA21D81E471B866F2037AD63E055953D2901AD88826
+854440E87D587F49854812962EC7C0B97DB8997C8EE0DE9C79F93D2BCFF8ED3A
+309F3D204B86DF1643C49FBD97EB6D3B0AA2B216CA0A9FD37D3A6F77C8E6AC98
+FA4C1A31BE6346E6E44FFF1B490C6C15049894F660E477FBB9501263D6A71F82
+E113AAB2D88A921FE0B40794C6C99C05DBB0822440B269CA52813CC324287120
+97137CDB0CE241CF06C43BAC889E4830896178FCBF881D497D4CB81E1882F252
+6AB05648DD5D95ECDB86704A85968EE36D99D24955D3535B28E65D10646FD7C7
+6F3C73ECA74ADA8EF43DF9D8187343FD240508664F0F4CC5AD394597F37B99B5
+1FC55E4045EA9139DE57F5FC345DDFD75E7F103FBB724DE84D8F2F21D816514B
+EECFE2166F544287ADE9F591A2244EA4332C2BEF8C37CBE5BD34ACDF480C59E4
+DD8970AE26B0DE389BD7535DEF80318F3F60C0199AD6024EE6B8BB0276BD969A
+783F9C3FAB57EFBD352B324BB8B36F818AE14338CF0D91B72590DC58ECCC1E61
+87A2D943C9A50396E2B334A36378BB3494E850111A84468DAB82744883DDBC44
+A1BE11334AB52EBCB2B1FBA36D96A97E5AE9C8E57E7FAE936DA892CF999C02B5
+95D6A2FFCF12CF643C435A6FE3E0D80C9A48B2971484233F8CDC79A6835DE776
+89BC0458C78B376401CB78509AC77BEC9656968B9F0B8E123CDE9B7E88B09F96
+E9E89ED4760EBE0ACCA2A6559002524B5519505A3EC5F905712989736B5AFAB9
+372A6384303FB43A02F8AC415BCEF9DC4ADB4AF280E08751A1FB7A804C1331AB
+D2C8A7AF8825A46D70D74E3ADCE5D752A5037EB630E745A329E29F51B6D5FB23
+C402E998CE580EE780DB5AED32832EA7B03668D0341B03B5E50E501A77278389
+A1529ADFC3313B8703E3B1DC34024D68F2EF91D58FEF9F50113B5AB5F6A38DED
+AAE24D20A5156E6D6B7090FAFE5AC41BF075D0E2A18119C3B9F62753AA121B6D
+4375A1024CA1E013440024BCF744FA30C4618C01568AC03C166407334C052EF6
+5AB4F37068E5D7D219413408B55F4DD41E827106CB1577EF12CADF21B0AE096C
+26399F9B3261B793E5165B35B93C7A0FB0DB9E19F7F8C255674EB64FC319D547
+1528F3E529510FEF4B949EAEC2B8BA1D45BCDA7478A3BD684D8EE00FC62B477B
+97A5007D99A4B14E080450BC08E62D80A406D6049E981DBD5DD2A9EDFE12F65D
+5B159F468862F9780DEF12CC9069225BFDCC9045F6F73A0AAF103448A076E3C7
+5A9415B0B8153DB4D7899FCCFDB3096CBBBC66F2787FC8521743F2596CFF4DD1
+1460A98705EC377588E77FD757C13DE2C5AFB1C9CDF5A9EE71E0334B0924B402
+B59D2185F08264356F4CF388D77C7F62234133A1D16085B357702298F0F6A253
+6D4248D29667E5B8EF31E991B42065F7E48658EA33F89240754186DEAD4C1D50
+5B983A6BBA42B9D70076897DBCAD22F924D55EADD270A7BD8450A4571CF092C6
+6F2150733DD7DDEF2095EE1F7B503C2A1E1FB3DE3254A4030A188E5AE4F309F3
+C3DB5235F55D128A6CA2BF8277F7F78129B057BC6E4EFDA79A097CAAAD25B712
+BFAE1193168F1A31BEDF3D07B733806FBC04543C73F506A8D137C722C47D9867
+AB220F99B2889BA49F990A932CCCAD8A0AEE05D13C625F539AE40E08EC0B8905
+45143BF51E92AB3191369F66604CF5A8E3608DFBFF28D1CBE2EA332E4616B8A5
+BFDF99A0F2188515148A2642547FBD837AD94A9EB63B9452FC714C83B5FEC391
+9AE7F79918458FDC90286E32FDB8B3D62787DA1F842466E306B849C9F16118CD
+B4F9A49D7BC027F941EF553C98CBB8178FC70334DC01640790D28A0A50FE9B10
+60018A930F231FE699BA8AC6EA3EF567B2AA462BAECE9A44B23A898D346EB7D0
+44022A11CFC50AAB2F3F54FE76F9CBE7E196B3EBA06C2222CD7F35A410A40E3B
+4E610FAC688CFB9EF5BF8DB068C4E52D5CBAC9637835C3DF3B36D00647C20A33
+D9AA954658D804EA6F833484187C7CD7A0256577FF7ADF9B8A43990EB8B3E82B
+D0C548D1AEECF7DB7B7DCA6B95E1AEB3F000598353FE8699026BC5624786DE3F
+A76D00CFD5B01DF639F2DD45C25091ADE1C86D52605E6746DF888DA05776C57E
+6E9527BD77C19573FDA86B38B75F650B23AAE3366C12D76B206E8865B2C5B3E0
+AA14E4F5177648626E7D383376BB203A4759C213BFE13AC26E34EBDC2D270E19
+2F4B54C1AD2970B8E2D98CEE84606D64C0CF19D7D4F08753D9B23093DD9F9641
+BB4064D2B4C7D0C1FA3E46ABC3095A4ED55A967646615CEFBBADE1254ECE0C91
+E783330727A8E28C0DEDE751369EE1E732806FFB0CBB1F1CA63AE49FF9DC17C2
+1702E2E75CF2B93C991EE82B635A362829D0D11733F89443F602AEDAF12391B7
+0133CD6C104FD7083F58894D269366222A127C25DFE29D934F72502274A1290F
+9D9DD6896E18157AABE670E482F6E02A646E6605E6D30FCCA15FEA0D496EF19C
+5559180A369189FD1D7E2F6918816D608092A138B34570A796B53F730E376D27
+605F5FEEBB0F36D1B1467D39A2D45AB5A297E92B6C6F2083E51FC933F5AB76E4
+A7434ACADB103C75CD4852D5CC7D101231036B240CEAEF30AA611A7003000ED8
+EE51D8668F3BEC852BA813B863111B95E6302CC213058749EC0D561B747FFDEE
+415BB66F819281E60D688ECE2C51F84989A49832DA326F36A20EB118FF530CDC
+4A332BA4F4C5329EF09D2B27B09D6A9F528F156ADC1F0ADF3F2A2B4715903E29
+6C9E9DAC22AC38F70B4E14EBA3F2E126527AF1D5E38E39F9BD601492B018FA73
+7591AAF7848CE01A35EBF654AD7D5F70BF0372F747EBBF55EC96ECFDD69507B4
+6B66E610281C71D408C680B914D522B43DF0173CFEC0F686E3D66227047A9E9A
+A884F6F7FFA624316FEEDF90DD3079969F6A9D96107D158743C1DB86D2A0355D
+34739B660D94EE61BBE52EC11ED84FFECAC5EC06910DFBBC7F6EB7AE3F117535
+B64F45507CBE6EE035268327F31F9D01A0DC853E0A8FACD0FF3E4746AACFAD40
+5FDBE45325E085463E3B5C48D7238A9B642F3234AF975352448563F8626E8200
+996A97DCD0F83128EEFD4528862C232D909C771C3B9CDD316BBD025613
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+%%EndFont
+%%BeginFont: cmcsc10
+% T1FMT-V2.0, Copyright (c) 1993,1994, Basil K. Malyshev. All rights reserved.
+12 dict begin
+/FontInfo 13 dict dup begin
+ /version (1.1/12-Nov-94) readonly def
+ /Notice (Copyright \(C\) 1994, Basil K. Malyshev. All Rights Reserved.\012BaKoMa Fonts Collection, Level-B.) readonly def
+ /FullName (cmcsc10) readonly def
+ /FamilyName (cmcsc10) readonly def
+ /Weight (Regular) readonly def
+ /ItalicAngle 0 def
+ /isFixedPitch false def
+ /UnderlinePosition -133 def
+ /UnderlineThickness 20 def
+ /CapHeight 683 def
+ /XHeight 514 def
+ /Ascender 694 def
+ /Descender -194 def
+end readonly def
+/FontName /cmcsc10 def
+/Encoding 256 array
+0 1 255 {1 index exch /.notdef put} for
+dup 32 /space put
+dup 33 /exclam put
+dup 34 /quotedblright put
+dup 35 /numbersign put
+dup 36 /dollar put
+dup 37 /percent put
+dup 38 /ampersand put
+dup 39 /quoteright put
+dup 40 /parenleft put
+dup 41 /parenright put
+dup 42 /asterisk put
+dup 43 /plus put
+dup 44 /comma put
+dup 45 /hyphen put
+dup 46 /period put
+dup 47 /slash put
+dup 48 /zero put
+dup 49 /one put
+dup 50 /two put
+dup 51 /three put
+dup 52 /four put
+dup 53 /five put
+dup 54 /six put
+dup 55 /seven put
+dup 56 /eight put
+dup 57 /nine put
+dup 58 /colon put
+dup 59 /semicolon put
+dup 60 /less put
+dup 61 /equal put
+dup 62 /greater put
+dup 63 /question put
+dup 64 /at put
+dup 65 /A put
+dup 66 /B put
+dup 67 /C put
+dup 68 /D put
+dup 69 /E put
+dup 70 /F put
+dup 71 /G put
+dup 72 /H put
+dup 73 /I put
+dup 74 /J put
+dup 75 /K put
+dup 76 /L put
+dup 77 /M put
+dup 78 /N put
+dup 79 /O put
+dup 80 /P put
+dup 81 /Q put
+dup 82 /R put
+dup 83 /S put
+dup 84 /T put
+dup 85 /U put
+dup 86 /V put
+dup 87 /W put
+dup 88 /X put
+dup 89 /Y put
+dup 90 /Z put
+dup 91 /bracketleft put
+dup 92 /quotedblleft put
+dup 93 /bracketright put
+dup 94 /circumflex put
+dup 95 /dotaccent put
+dup 96 /quoteleft put
+dup 97 /a put
+dup 98 /b put
+dup 99 /c put
+dup 100 /d put
+dup 101 /e put
+dup 102 /f put
+dup 103 /g put
+dup 104 /h put
+dup 105 /i put
+dup 106 /j put
+dup 107 /k put
+dup 108 /l put
+dup 109 /m put
+dup 110 /n put
+dup 111 /o put
+dup 112 /p put
+dup 113 /q put
+dup 114 /r put
+dup 115 /s put
+dup 116 /t put
+dup 117 /u put
+dup 118 /v put
+dup 119 /w put
+dup 120 /x put
+dup 121 /y put
+dup 122 /z put
+dup 123 /endash put
+dup 124 /emdash put
+dup 125 /hungarumlaut put
+dup 126 /tilde put
+dup 160 /space put
+dup 161 /Gamma put
+dup 162 /Delta put
+dup 163 /Theta put
+dup 164 /Lambda put
+dup 165 /Xi put
+dup 166 /Pi put
+dup 167 /Sigma put
+dup 168 /Upsilon put
+dup 169 /Phi put
+dup 170 /Psi put
+dup 173 /Omega put
+dup 174 /arrowup put
+dup 175 /arrowdown put
+dup 176 /quotesingle put
+dup 177 /exclamdown put
+dup 178 /questiondown put
+dup 179 /dotlessi put
+dup 180 /dotlessj put
+dup 181 /grave put
+dup 182 /acute put
+dup 183 /caron put
+dup 184 /breve put
+dup 185 /macron put
+dup 186 /ring put
+dup 187 /cedilla put
+dup 188 /germandbls put
+dup 189 /ae put
+dup 190 /oe put
+dup 191 /oslash put
+dup 192 /AE put
+dup 193 /OE put
+dup 194 /Oslash put
+dup 195 /suppress put
+dup 196 /dieresis put
+dup dup 161 10 getinterval 0 exch putinterval dup dup 173 23 getinterval 10 exch putinterval dup dup 127 exch 196 get put readonly def
+/PaintType 0 def
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0] readonly def
+/FontBBox [0 -250 1077 750] readonly def
+/UniqueID 4701554 def
+/StrokeWidth 0 def
+currentdict end
+currentfile eexec
+9B9C0887DB83FB1ECD8335B0BB39CEF0AF64F656FC6E5C230CC9D3A7346AAC7A
+06BD9A40393CA15D3773A21E06B9B4254D3050E90726BBB09120935A8D448CDB
+C799D90205A21291254FA633CC0C2ED88781EF21A5D45B72445C284FA44F8F39
+CF566976075A92E9E2947A6FC93D879C29EB26809ECB4409CBC8666526CCED92
+65DE661A2F8B0A16BE45A9DA17EEAF89B0E023DE2B0373DCAB997D60B7D7DC1B
+4F7E650A2A9F13CA0543F3B080AE33D65F2802B8C5214D5B61835338CC208D61
+05501307FEC48CCF5B84971F31AD8A4F0D23FA9336F6689DC2A56B553F5B2A4C
+407D9378280A95C0045B3F9D8F7CB131CF4AD2EE859810319EED4082B193FB63
+E16EA0D69C0CDB5275814CE04C6558465A99B8CB4BA8BBF2B568FE1A857FA569
+3CD90069E5A446B86F82FBAC48B6C25F332FFF0FAFB04725D227FC28C2031D90
+5095F829EA6F1D8497077F2FC51BE3F59280623EA7A7A961565AA29ED4BA0899
+E22FF1EA9ED97089659AC56818A44A585772405409885F335E48C73A173CBE5D
+52152759C8F30DAFB9E62407BD9AA3E1BD0CF45922AAC1982E7CA503AFDBC369
+2D62F68D07D83728E48C6B20B03890E45C5704A1E39127CF6525C4B951EC968A
+3374ECC8D7AA22C66B5B00BBE6843E1C544AB9E97B4787707080A58921C1928D
+0710C0F6A84CB91045F715CADEDD49CD06B2803654179785E07652E16B5D5347
+8F3393187212A3E98A5D13D77841CC9958AD5E0F96B23CD331659840A36A407D
+D2E7A6E58C08ED171D327E376E1B0A4ED61611F2BD7BB7AE16C36A1DE466E8CF
+69023E818FDC75ADB6BB6584ADBBF8C5632015F42F7E948CCF12A5F28A092035
+D201571888EF8CBFB5EF8AD472767422BB58A773C50505058BEF8E03D6EDF29A
+3A32EA06AB032E65B65571D32FA8992D89D53C8220F05421BE0AF7A63CF828A7
+533CDCA7E445BD866989F908E8BD5C9EBAFC11F109EA1FE0B99B6E755486A034
+036F4A7D0B7167C1D8437F7E6817384A2BA7C492E76C313F168D1CD69268A02B
+493FFC076A52F79D41EF492A59CBA939ECD8418F58F76686E3648342F8D81968
+96419988BCE8A7473D29C44704AF1F54A61185621626B5ECA3D9DC1ABCA4B82E
+8421467F921FF8BCE016A893DC9823E33E774015A09E9DF2685B2597811E73AD
+417166CE24E3D97280546EA2B5A8B53281D40EC512E3D913B57E8A6666918875
+B0CA655AA42838BFAC8BAAEFA380299850C490A109B38B4F462DF9915CFDD4C8
+F4725200960631339DE99F9738D8366E70792A26F07177CA728ADB9FF8090BC4
+4309BF3058308991B3FAC3973C1F1C3B1C19C87A6A1562979939705520F7C977
+7D1ECFE515C9E31C1C6D7F403299CFD8547DF23D2A84AEE11336C362BDC205E8
+6BC7AE696DDB26B324631A831848FC92786C8A81458881C2C732A7683E26AD34
+0141B9DA73EF291762C2F608CD983ADFD59F30A73DB961B7346BBD89730D3031
+3839A4F389B2113EBE554CEBC6F1A4BDA35F2D6042D8470CF5DCFB4F0C3ED526
+D45748AD4BC5220A633B630DD00C64D870632E4CFE4A2FEBEEE69381B0D35CD9
+080EC8CD097706040DD8579BBE9D3736912001CBD48F4F163F4FDC4A83D91441
+0FFA6368FEDBCC957FD46266D2D53C066DDD86698A3BDCFC757B126938B58BE2
+AFEEC58928C85BCAB2670C92B733058038A4E539E9F3BEA9374D6EF35A53007F
+83943AFD91F8DAA041EFF63F01CE340FB0C6BA796FE2ED4DAAB762CC0BC47761
+7E267E09460DB657B2BD4799814630E492F23223D1366923C561C3D0D2ECC1AA
+F298A4B8A384AAB52E55C19AE8D79A918893061EADD1751E3F8248677AFC7BA7
+6513391CBCB6756040B61C68AD1F4F54D372A950EB7286A530292EB17ACBC846
+3517C69AD8A41021401A72E09CAC9868DE0DD1FD2425FAB79D488E95294B58CC
+346A0F8B4DD79BDC32CB28E686589FE9C87A120CB1982DF7F8436D6E9F01C1F4
+71751F33736DB9F50750BADE226432BFD95334492ADB192FDABBD4F38256106D
+34FE08D59AF5DE367F68F6F8AD3E47F274B3713385AE527BF52445A6CF07310A
+A50B99493F05B148559A0B2EF7BD5850A5B1A04D769B0190B933E5834FC93663
+70BD77D73E68F5556B8BA3E7778D161B8B4C4B1887D27C0E9BBE13365FD4FC82
+D6EA2A86E2CB687A3624B8F72AEEDD6EF2EB23DAC77B64B737AC748F8473851A
+081C5CF12A66E5F8A815731EC8662A4C825CDC15BC157693B6057E22A2AA71D3
+83289A9EFE6F9337ED542A3F6AE0CA2321780130626668B9603ACEB9566E7737
+8D94316FD1B86B580D028465C06FF7A27821218D54ADEDAE796553063E2F52D2
+9552A0C89E4AC8EE8119E1F70FCC9AFA8C01171B252BAB99A05FD03EF9DCD523
+8C7B6210A11B3D4C4A45404160A65A9DA97D2086E33078C52C75AB63485197D1
+B37588CD7F3D190A3BF96588778D022A3B025747499505EE3377818EE8FC074C
+B79216C996F1C504B1B4FCD987721331035FA4C8A0CE71F59D07313A237DC76E
+A4E4C4C8DD418150981492277D12D17F034D363BFE9817E57A363B1E5A1672F3
+2F81856FC2AD67A26E506D69FD2E12ADD96410F2637C29B0F9EF7754CB05C4B8
+9B87148C40D213F6E4C6C78EA84D6D667FE31741983F34C969944CD736BE6A36
+C48A9D5C80B62F86DE19613EF0FB94947581C6CF37F7ECA9F2286A6415B99850
+226323FE559ABE8509BB8DFEFC3EA7623D0E9DE6B070FA1694D47678BE925872
+5663CA0D4B6EBC6CFD7509FF764C4BEA479F6A7FEFAF0FB04030B3E1FA569202
+461A7B21ED453E81357C2502E60D6A195347A9B1E48B1F10CA3AE9FE6E3B3F9B
+6F4653002E78D5FF531D64B6E607508C1272E32AF385481FE48E16A04E917A17
+455506F5819A825B9EFF14495DF6C1D879655441C14371217F675F966F6B3863
+8A588E8F1C22C829B66931087F54C13C30981C64616731F08136A1F2E94443F1
+161A599BF0AA225C55C558562C1ECB69CB6479F61C43BDF0366ED8EFA2C6A93E
+7E03777D43AAA368D1B897547F6F3EF7A4662B942D32E57DBFC4E243E8B7249D
+DEA0AEC4F28E74D68E68D098673DFE170F3689EEB88D296EB8B86EC84C0B6FC7
+A8C7701443C93F402B09D63D8D88E67E70A9685DD00355D4F97D924625326C45
+7783C9B3422EFE74302C88FC682C7ECBB818235469BDD6B108B6EC44ADC9092F
+2C132416D4B439EC1858E8810F1A50E358744AA78156F5F77CB23D8A7FC7872E
+F9422DA51220BC41242CEC90D1199D11E6935E70415F246687D015AF165EF4FE
+75F07B7FB28A860A8DFD786D972896E0E7B094DCD9D0D933D2CF264A71CB6B35
+809EAE5C0B0D75C271B6C6F22484191265F2D73D41B88291AC42E5FE2DB59D92
+8C3E33338DBA7116CA2F045770D459F9D28E44496B63F1F6D991BF0F9ADCEC85
+D6CF54F4DBE12BCDFD5305D5E9A27BDD5C24893B74B81F287608A07526C6859B
+B174C70DBCA2A8C3EA5AA711F337772C4FC741E4C0C46786B05D31E39AB20EC8
+CF6FFC52BFEF692F1B02F1CF3F79DCBBE675BE1DD6F4974F0586900E4AF4D900
+38EB160DB1BAF23650DB009270F4A679B8751626A5F15D3880813DBD574A1B8D
+8CF16E050DCD582AC7A90118F2756B106AF2775AE90769E862E684A1C12E73C9
+EDFE5A79612C54EB7D66FB2C142626A308ABB7F81902B231DAE57B34476323F5
+23B830DF72A6BD7E42799DB042952B8AC854B47230F2CD171546E5218F37FD87
+C8513642DB167A394914C6037ACFE16CF47E783285B6CB322E5247416A4931D3
+70CAB792E72D00934FC826E99050CE6F1D7BD5892064E1682053B34270525F5D
+3A6A4B2C35CA1F0179C9D342C0C996144412C3E1C283B52705FE9134018B4093
+D391AD7F44665D3EFD2353B07A8C3310E92D17459EDE74CE0C9283E34341A7CC
+56D472C6971A260B156DF12547DAB727F4E8F9131F6CBF5D60E63EE56A580C15
+49AC12A9CEF939E0B26678C4BD5FD00A29F832899A1F28C75EB58F32F5CE54C5
+3F12E668F0F04AB9E546FCC2140858496EE9A200011CCFED62B3AC24EFE8C2FE
+AAEB3F62F9FB23CCDE8A1258027FB3F0C42862C1F2C556955082C3EDBEE42616
+80EFC22916B3DF99A38D533B5975B1856FE7B879B9C22EC41309B753F4DF65CE
+1A39398D3A8AA078B243BBE33706B9D3318045F966F25DFB4CBF912DCF522C0A
+1A139C6720967118EE918A3868D2CCD1328EF16C4FD0DCE6479E5BFB64B040A6
+0116EE6127473D81203C797BBBF0F1E4623FFCC67087B34DCF95DB749D0907A9
+D682754AE5CD3A69C3E2B95306123626C81CC107C4E8733EC4B7FB2D43131921
+DA5D058200AFEB96C2443FC5BB2133A4EF1172F418ABE3B52E0D79628576BCCE
+A05FE6B149FD919FD0CDDE55A4FF25314F9254CDA6C901ABFEA25EE6E125AB35
+FC588345FB72F54D62FAEB54802741195EFD57EA07FBA9331160F74A29FC38FE
+6CC5E6ADD81D2DC02579ED33CD48860B9F45DB77AF8276B4C6F5B55787EF4AD8
+80E3908A6A1E424559B7473171BF79E2C3F8ABB541C7A5676F8180147EF946F8
+FF62844DA2C70D75AE3FF568C256FCF65887BF3864458E8D389E7495C4E381B7
+F22A4A035E3058546A1F201079A3E6024F68B462C28A955801BF1CD3E62D9E0C
+DDDB36DCEE6D03094BF61424B15D4C316B6F6BEF8AC813D3F0CB7262B3CAD2F7
+B71DD33C0A63C9A04049BE954BD41DAAB34ADBADADC92421676A2D39BDFF2AE3
+41977E42350537754799026504B8157E6AFB8427EC8908E6D8AA659C6B21C79D
+B4D39C720565990FF48B76ACBC0E49FE661570F3B7244AE0405C683E8B264087
+84378B700CF8C69E8CC9AE677A3F49E7E65C7EC49B5A379CEE5CB21F8D90CCED
+A236D850313F93867253105E6BC79DA26FECDEA83D0A7029F2AA4C0B3EA3AA34
+980CD60428BADB0FEA87B2C8445BE826F7FFF50E51F6868923638A63621406EF
+14F98248E24E0A3CF6665E7C52876B2A26B76E54980659AB15F5B8D590B462A2
+3EE48BC7AB5FF8AC9327498FAA52158E10E002F17E573309E64F14488F32D523
+06B4B263A1BBD5F5F6267396AA1556007F77FE0D473438CDA6BC8A550C448A22
+88762A7EB57601A5C6803A84499900E1346FA5D33E1B1D008CC6B8705C90EA25
+8F7A7E2F08C7B3E6542D137327D6C941E4884A4CD9E9CD488D1529A9A7B495DC
+4E3193C6FFDB6BD763559C6E9DF8616804AE881A03169708B122C22A0F6DD0DB
+BC2D86D0A8F1C3AE748A7052178A05FE8200E43FB229D6AF37A409732CBFFA56
+D3A4F163036D2E8A80D62430379AACA3A66753D47F441E31C1444382E6E874EE
+1206E550A7BD2487E7D3646E1AA4D57BE3FDD563824932F04490617FF3369B7B
+473863FB3FF702A47A2FCD0CE3E845ED8335DC453F2FA794840715B0A14FC657
+0F0ECA578B03E637EC62933409C72DFA5A8449A00F7D5B119961E503984CD2EB
+FB1786FA33B2C5EF5DE334A853625654AE4261757C5E3AA266E727407232D218
+118F29CFF96BD99464DDAFF8295DDF7FFCD59F2E7390DC253049CEED080689D6
+E0E7C962C61B4153375BB4FC24C5E08911DF431AB37A08A85EE0B7CBAAA01270
+F7CED06BEF56DB2A663C63EC03B5931D7B7AC47601BEC3FEA830A32E6EC8FAEC
+043808693211A6021B2F28D9A0BFFC744ABEA27445773C74FDB94BFA3A28C9FD
+B7E531304D95F04C4EB9EF7F8F1AC756CB1D3F335BA3F5E52339BB218C21130D
+7B982020571F7D604140E8CE8D6343380D52AEA18B707F0397946F8E07CCF8E1
+1E18237AE9A3680920EF6D0B9F6D4B1B34BF867B1DA878219E712BAEE8A5A25B
+95D0CDF979246C5E63486640CF469E8F505DD0E0518D672F4051F0A327458370
+542DE27BF723CB894D7AD17F38E914E093FAA5DAEFA82A1BF6C83DCFC41FE4E9
+D1980B1D500FE754707C02B98BEADB0BE51E6BA92F87ACBFF7F8E75B5CA48378
+DFDC891F71DA637551A4187A509C9DA6E618C613A341EC5660C12B33B22843AA
+7CE398AAA35292C5034572F79BC10F4101E0E54AE77EDCD507C970CFE5FCB4C5
+ACEFD84B48FAC3BDC999517A4E309D8DCD5AA52C6A7015AB4AB6518D015D3CF9
+4EFF7808C5C3C05388681C40983F330C8FDCD93D2874C24C40C248AC57B42493
+DAA88995F1CA7ABF74B13E3CA08F4A4739E043F5DF3435069FB184F8765A183B
+4314EF9CDAB127701347CFBB88E4F6F89B91518BEBB8E594C5ED80CED72EB401
+87241DD0C0F4CBAA5E6AC53402642F85E57BED30739B81AB79D16F7135BF8298
+18D251507D91D9967A974FF10055BBE63F3726CD7E388148F28C2B3800737FAB
+302E6877372AB1CFC5EC66C8753D946517217F60A5FC40B00E95A650E592478D
+5C8A8CF1BC1E4F7E86099E56CB00096EE6A9CD98703B4CA172ABA8FB16B3077A
+4B109AB0A6E4C0CDCFE7742EAB4965DD666BC474C966653556693C4290434F23
+184882BD6534ED0AD8F9D298D520C077D7488AF8077B1968F0CACD6111A5B1B7
+C7BE9586520108B932920EEC6F98EEF2036D6826EF1FF61DF6B2A5E7B847A3E2
+D2E83E69A98B826F806A67B193AE07A1D16F12965D34FE1662CCEA459A27063E
+84B223AF04E1D4DB52B894AC4AC2FAC3714EA4482481BA5CCDB7D0303386C753
+4BF3846B5D3731AFE6CB28E7CA2229205AB9365A28C5A362BE242AE06F8DD5FE
+C2471A010AE748F4A48026AEE972FE804BB7773E15EC36F766ED5F5342AF93B5
+D21A7585466641A6A4ACAB3F4F5DFF71514C105691AB636E3071E46956BDB6E8
+9258ED606AAF78BF1CFBF5280D4A039F96464648DA76495804D2BFB2B452078C
+7AD1A80CA94DB4086314AF1F6953C0A8742E6DC577AB32C3389BBFCCD2893C97
+9ADAE394ECDBC855CFF5A7FCE17E32803AC7869E8AEBE94E8256DC6468FD2646
+31B730547958DF3C878F6DBDC65D048285F296D3D6FA067528B4663116FF4BE6
+2C3578668B3F3BEA1FFD3B142D4073C746231D8558A9F4F1A1AFE478DBC2EDE4
+78CB7795BB80F32A0D266E222D0AB34DCB18E17ACBEDA779623E09481D8AB1DA
+3A6EB42BD7C7BD071269BB3FF0E5BB1483A9D250F07E19B4C1E2504288E6A034
+A7246343B50E1FDD622AFD081C3285BB5130390FBBD5547CE34EE80DCB810208
+C0B2B86FC15F494EC25310182FD011CB1837107484572294CF2E2C0F3F55B2BD
+F2BBBEA761B8D9DB29A91B0906961ECF6DA690DC768D9F937F933C23668F0F7B
+D8E69756AD43B7DD15268BB206F9D797607DAF18700A786C5CB449CE6D66F221
+BF281175340D508490AC5930D0D6B7DDA6646227D126BD9B7A50A134034B7D64
+DE1CA653847AD3CFF5001ECBAAFFFE074E356499D21D0ADCB3CD5BF3CCFB4D79
+BD72F8EFF9EBFAE629CB45BB1776AED53AB18CB7E515A101BADE4C24C3ECD09B
+F0E010653DE7F5911C69888D0804E01EA353741B7E1FAE1281D9EC7D821B2255
+FD6C8F3E243027E60152937C777EB4C0DC62F9F0D8D4EE96875407D8ACC7AA34
+779AE87E41C49DEDFD6304D703121AC25D6E9A0E3006D423922AB6F58B7FE0CD
+B7F5BE05BE5F499777FC4FB5BEFEFD1235629C788D4AF8EED596942AB3909826
+421B649434BC2673F9659119222DDFCEC623238DD0CA0ADB662B94568326E522
+C25EB48763D44DFFC79CADF6AD816A3BA2D42B9C1D6E2ECF5BE5B0D2B3766EC2
+9BF5048EA59E18DBF4C91AA748FE18E4AB6B768BCB4955580CF98528D97C87F2
+4439955D9D5E73D0CE50240FDC7C0A3A437A1C8733CBC829FD911C6FCFB27F35
+38B61C235172F755F2720447C62B0F20CFE9D5EB611661BC391934F883F473AB
+31600207A21FCD9C4F48113E5075523E84081706D6FCA70D54C7E5389B9A66D7
+ADAABDD0616E07B2579E997502A4208060371D61E957FE380B6B48802D88666C
+B29EED98F3AC3C2AEF3ECD10A363306534BD86F645E512BC6D97BA51D621F022
+603B3ADCFE7C2EF109D0AAF094C2B29CA2DF77B8AE90BDF43F7A376D8002AA72
+517F75E08179F67819308E9E76448791EC8B0C9FDFD07B43D4BF1D71388C3427
+594860D084A34586BA8E662942FFB8E97A08DE31F764BE4B1B01D83416EBE660
+609E22B574376FD7886DBF1C5D350C6A1A0F148D139F9301BEF6F4BFE796C9DC
+35EBB8B9849B03CD46BF3DFE996B12DF256B0FA8AE190203501F06BD2741977E
+61D1FFE8775434C85E58207770B177C1125408DE5BE4F4755CDDFD10EB300123
+2E380128086D7F6FFA2C7E9F898B1F76EFB5DC121F134378683C1836F800362D
+DE7582775D12FE54A80EA4721C85E7FE23141DC2649F9CD7A22C8838B82659AF
+1C227D10234F298E5DA1125FEE1C42F924E5A341D8E548872E15DB3CA1D0006C
+4543383D7870236090B6B151AF797B803D802F56512D5433DF9F863532A70448
+8988F959A3E10D2A7B8F7C1349362B97E9FF96BD60F4C01C7280058EB3D6D3A4
+D2EE22AD1945156C0DD0ACBD1BC7BA2F28DBE12C6E8CD8C7B9FC376F46369E1F
+7A1D948EC5C1C5CB03CA6F8DD19BD2450E3132052304B82016A521157CE0C085
+264555869BDBD9C4EA06A6E2305C3F8DF8B48267A7B216BD321671BD7E781EEC
+1567787D43895DB5556D0099162FAB3709F108BB6A51B249B7CFFEB2ADC25EEA
+26DE7DE905BC52BED055684C12D1651DBB3AA3EACE20AF48BEA6BDD6B1BE1B80
+E2D365E7C1FB662086F4D51CD4798EFE99B5910CAFD0A9901B9424693771CDFC
+19567ED5E003EB523495410B810B3EFDADDE0D2F66C27E9B7E1CFD6D5EB49C5A
+63F239C964EADAF9B6C0994BF5773BDA6448F69DF078CACF8660D9AB8BBAEBD2
+6EAA6B503BC4742685A99689F46BC0FF50AF35909EFC978A523851C099974B64
+9CD59766246A7F7E1CFD36C16B3459CEA533ACD5D718884E11A8DCFF9B6CCD43
+D53ADEC4BFA36F9D878C18FA48FA538CB47AFC1366AE1CEC893466D8713CDA39
+1A08E2A32A495E692FDF4061DDEF5FF716ADD8ADFB1F85E2F150A7CF2A4A01BD
+1C93C833EFB20DCCC429E35493E603A7A2B0246AB0936003DBAE7800EF36B25F
+7A7CBD50AC4A5863320D891CFC05509F6A3AEC29A2B21565077D23DD03363A81
+703C15D72627F8DC414C3B445B7AA0023253215DEA15ABC2C1F159481AAAF9C0
+AE4D4FACBB48CF83A3480B79D9F2E2CB98C606D78ABFF4F94B2C09752A31EBBC
+946FDC415AEBE73C1A85D379A0B99016B6480AE27EA95A83CA35A7992AAD4183
+C42BDBD6190B2198CC0B48450CB65C22CCFCE1A81C0620712E8332F17C48BBF2
+BEF35A67F0840ABFA1B40FF14B0F217D071C5B37FDDEAC519139B88AC04C52E8
+52D057FABF743C849DC6D3F6B1275D5FD173F0F25C31D55DFF6498C8161FAD22
+57837BDB4FD169A17F45D9214420AA797D44A1E33F7F242BB6ADA2E838E217FC
+8F85CF785146CCF4759747F549E5F8BF5828EB86264D67617B912F3B1B6CD5D3
+CC1D33F5C15F0D5B23F48C4DC40FFEC56D01D78B2D6BF18D77421EFFF9525E34
+00F389B6FACFA172351DFAD20E84FD7A9371BE9A5BFEE4AD8EAA458CD66FB6BB
+6776DC59E59FAB1B8CE9389220992E18AC7CF1CCE49BAFA7A0B401E300B8BD7F
+83E6551504899EAF9A7338D8DF4218A541CA447AC234FFB0C5F08540F9994B8F
+3B6CB6D3F821D60BF3E6378737857435189325F3DC8ABB3E95A3FA19276BE44A
+B17C282CCB5FD2ABB61CD73A6DEC44F25034DC4C153F436E1FA799CDFE808620
+D3C80EDD9BAEF48E730B37EB2CABEE4565DE8844B48F2B041F4528F78795FB88
+E7EAD240C1E5A985AAE1C45EAA9AEE4C76E05610124A3B703C710F414C5597FC
+B9DB61B13B758D4DB6AA9EB57885A07C751EEC98195F02CF945BA2BFA521422A
+47628F63D14308D514EDC92691AB271FC52570687836C84B8DAE44FF6253B3DB
+DADDDD9093745EAD3672817CD27D5C97B4ED800200E0017216DC8C3966D146DF
+65ECC0E35E6B670178B9554BAC4AD0A0CCDE4B271359D8AB712E2CCA8ED74DC5
+CF438CE8A6C70F6E7FAFAC10F4C8FF6928160439A610E744281D00F99642B856
+AC663CA99600BE0903801237EF19F5C699E3D5B076A645618BC8C19A5DC3E690
+E39F5F582FADE9D140688E3E79704CBC2BC655D796F2C15883E09BD61A700FF0
+292860D5BF7E3E0EC99CFE409C8CBBD0753C48A938DA8D08B43AF97D89D4EBCE
+798848195356F095FE6B0319A93F1DAF482B3B1E3ED67236215CB10D85673224
+CD4CA72E5CA213D81971C1B689F72FC341EFFA8BFB27B98676A3F58F96722B81
+552D0C57BB4EB64D6671DDCFDDEF9183BCA627625608C711FF8D593B4904CD1D
+30B4C4F0BEB010624219D0AE0FECE41E77059D811CF34770FED28EFA0D7226D9
+ED3A5FF296B8B7DADB600E9D378169CB20D03E155CD67A27F253BC32886730F2
+F2CD5EFB2DF7ECA8B7DE116FF113EFDE8D1A279F785350ABB361D228D7D45565
+0808F17A2A7E9F96876CB0645659143D92F24D2BAB519E6503B6556ED4C8BC6A
+8FEC9773CB8A0EFDF598FA19650209E15548139CEC8D888F4FB9A3F7B5E35F58
+C28E344A9A73AE19E0E3990195C58AAA29A3C64DA97FA0FAA27585ECEDE23743
+62AAFD6431AAE6185D8611C4F7EBD607D488BE416D56603CF7BB11CD77472500
+435C40A75D06145000FEAAC8A946B2AFD2A971E8FDD34092919DC6CF3606DC83
+4BAFF20C1B9D2E5903BD17322F43B797458D910C7C68B233A0B8B40EE1B6969A
+E6F12D44B94B98CB3EDF44824497290B609037645C85E55F6E6494A44ECA5DD2
+FCFD98F8007F396672044E1468D92D1B06A3597D2FBEB32202DFD3C495C7696E
+21504A670558F6E6190E319BCC7D84FBB7D8E4F35C7E6BDF380F4B1F0A0CE29B
+784A102B950925884792A042463013C98AA2105E957CC0FBA0A8BF5A04B0F99F
+6EB15362711FDC8759731B6871FB1E60E47EC0396151041B701677A38D0A4ED4
+B9606D5012EA315459677B3C55604E2FA8D3D47AE694FC7FDD0D056749A2E1CE
+BB69C67A55E7042F533F17D672E42C8E0C010D72CC08363552342FAD57E22A59
+758E895487BB7FC03D3864F34C3AD10DCE31A2F56BDF06DE3B7DC2E32BDD4207
+CE39BEEC5AF69B1E1660DC2DD8944E750CBF2EEFF15CCB968AF9BF337766F3BB
+9DD9251B3CE43968B6227C0F6806101AEB98444154D645CBE85B9E65FDDFA14B
+684BBA8BFF7A1601C6A7DDDB7516F2A69B9F5D542FF78730CAF42E71C8A1FE42
+105B27283E8AE999A8EDF8F9AEFE51ADE5B2091AA0C5EC78585869B7D50C06F0
+9BC5901017DBA6761725CF639A01A969AFE8129BBE7D1CD34F338EAEDF1A91F6
+5A21DD9C507D0C27CC2DF65C2A83D4C4C1E6B57A4F5EC799FF44D3AE7057D243
+AF16232894EA0C963790D3278351CB0EFF42AD43DB987F9047B0CC063A64E04C
+E05D8F2C4E74DFE899B61BE66CAA5CA613BA0EDB91494B9B613B1609A0F8F6D8
+83062887E7B863FC2E97E1D97EE99B6930F42DF9E1928140BCFE3E5E933B826B
+3F537F38B8E7565FE1EEF802D30F588427413D54D8A39933BE75001B4B770468
+EFC6393F6810D02E5DB1A7348118052A00D6E4C1D4745D21ACD12C2516FDA833
+EBD94168C54B1359AB670CF86F1CD00ADBB64A5E7E88C701FDBB10419C8ED9A0
+1D262210A0DB2E03A9FB7F82332966876EF675CB4E0619E84163DD97EE146B8A
+B0115C7700C337F637563B6B7DC304FAE6CA5D0E903E9FBA76068B9F3C72EFDB
+6C9B1E5F14D88DCEB689984A0D2552B881FCDBEA55F7366BF7964839CAD1DB43
+C0F2386818F1AF73F2177C2480BAD174DEFB2327E750E0F50B4FAA3CE579CEAC
+B01380D55FD25812DB806997A5446628BDBFF77ED68F3C16C016542AACFFCC0A
+FC2684CBB5E77AA8451DF512EAB8F15DB7219957231198870DBCBD035C69CF28
+26FF833F889EA78DD18F4C14E1DC1016EE22E529800BD8C879BC142EFE38DB92
+6CC07F8370D946E174B6CE530BF7B717ADC5B4E78381E1B144B1098770189BEE
+00984781EA356F451A59F161A2C8588778776C66F82C8C2E6923ACEDA5806E91
+2BBA20C568F69F6AE3946F3333608E8FD2494B194BECF0D300D5E4E909FBD60B
+FA894A54A62D00CA2A46F5B4DC2D9A9F3A5B0F04A0A9E535EFF3EFF7344F14CD
+5C9296B6AE2E3DEFC7D3DAA5E652A3C0F22A8F6EC1AA8B0FA785675AFD4CF431
+C35D26A7035FF7B72129DD48E7FE6A838113E1A09E47A35B2F8EFAF2A1A8C215
+9E4ACD754E6284D36716118FFE3AABD8139E57E9030DC0DA9FE790736DD0A67C
+03D492652B66E0CE6A6500691D8BD0EEED0435533AA31D4DBCA3DA5D117E7E95
+0EC20BA7052CEDBD9BBA30AFC68900E998EE69E1B72778287A233B2BD3CA15E0
+F989DA35E66A602AFCEE90C6E8D877A430486B8C000717CCCA9E3FE551A08E7C
+E9023114FFE56A1DBFEC17E59165DA7FFE1D7C43793B7DCD3E40A79E35E417C1
+E10A9DABCE129A79A9B3060C6583FF5FC3F34D5A519D33C4A9E1DA84E492DF7D
+3EDD178FEB9764D0D26C4CE8A87D77A3B4BB682E3534A4D31E7D25DBAB922222
+FADC2B82BB2F5A4265E09D55B0701AA802563B427A1DF4403F083C75401208A4
+EA2B0A03F9A798BCED351A28F946B47797764372FD63084563CBBDF0B2B84E21
+5A3FB819F9591F3181243151B333690B57D65A1CCE64130EAE728DC69ADD89AD
+2CACC21122660A4E7FCE87038ED4FC02C62CF03B602EC2ED65CED0FAFC3A4D5F
+5B953122FF091BDFC0CFF121893141A1770B64631CCE4016304C14313399248B
+29FD2750972DB466A7A7ED56BC2A7C991753F138348ACC1BED3A1B8BF0B74146
+CB09D777D2145A6341C88F44CBCD6D0E100576403CF176AC66B80414174B2D46
+09256E4A8873623EE92C2A3E3F8EC40824424B9F09CEEF598A84049C3002A73C
+A68607519E4599F35DA4E8FAC8DD6D3C7DB490B188C6BF0490D9456A3BED1A8E
+13BF001015D9BFA3ABBDF88BC4F3582210B6BC71B83D93E0713AC5512D70E61E
+1F96FAC3E1F313C5D29F0BAC11667E5B28243B9E5AA35E597A5B03969E65BC7A
+8DA8D07A049B2C69F2BB6F163C1ED5794AE03DCE4660A48952622C48AC96F662
+A5DC8D7676EFA86C5CDD3E4D5C0AB0FF68DB756530CA204A8FB55955F953C29D
+70530C6445418A198991E043C57D214A3065B420B679E35D086241B2BB48B210
+1659E53C636A90F01E0F7AFB94DC41C2E83C1D320E6AD0D61DC18FC87C2AFC33
+7F2338D2E71A5B99832280DC3B27FED7A86731C106CA68BAADEEF1A8E77C8B43
+71D51D0C898772AF1233D8AD8372698A603FA2762EFE64BC81E1F7E98A3209CB
+1912D11373A35E9A80397CB8B15A35B42C819A9A174E07C28E6D660D3A622DD7
+2AA79930B7061541C6208DF061A923A60F7480827C47D78513C6D0A6F382EA11
+AF29E6836129DD7F8B0243B3FF3C9AF10F75147F96C854EA54B7DC37AA412E9D
+C2468C7737BF72F2FF771E104E2A9D24293C9A0DC0CFA723226DEB7EBA09F317
+B68D8A70853D708757EEC9941A4A07122D5E2CEF04A9746CE4995476511D6BE4
+6F0F6AFAACEF56297051C1DF6780FDB649A641340A61CF83A8FA93A2D03EFD66
+A7D5693AC165508FE169C41C8B697ACEFF39BF22E1E23B0E7B5C72CE2B487DEA
+961EB3D1371137F66AF4B380802780C0FC4E68DAA86EDBB71647AE0E31C88B84
+B87CF2A69AF1B151B73F299042C5F7703DCB2CC8629678320DBAB9C2ECA249E6
+0AB435853082E93BD5C019C88010F6CF82B46C6C7F2B31AE88CF62948D76EC98
+09871BE5549478FA43F147EB95A52CED2AA23AF858CEF90A2ACAE74C54C23554
+DAF59756360CABCB2474A85A441552BA3FB47377EC29F2C6A1F67659584E3B51
+9792D29657A8C6C1C4BC8BAA96ADCB7D2AA8ABC3C66EF8BE6DBB304549D764C2
+2CB9210342CDCDDF877EB7F2A73CDB19E5D05B11C480B9120547A987B87169C5
+15E8210A9FFDB7283511F50701528BB8DE8D55BE050D477CBD3FE4B1E6911CA1
+853F58089C8010B2601D67E2189C29227CA593139B00ED3E403761A9CDA9BCA1
+339BF77815D94F2F5D9072186F2FAB3B80A30073BE14FB29B7CC6496FA892FE9
+8EB51E24AA615D5F3772E03C6A87DA211D3B86702648300AB8905E7C3AEECD2C
+2FA61500207DF72B2837F20505278C11C572BBFB172F5461AF07E1A88903C9EF
+CF7275A02E81B7038F1ED00DDFE60A90E0B3BFF35502FD370BBE91D2E0E5CCA6
+79971E4C339B8CF337D2FDF4CF0C084AA58E6AF16C06F4034DCD6048C58DDF2F
+E51DAD62C29D34CB13FBB16E7FF581514E16742B183D6CB6F12B21C3B2758823
+52CF4573322140D0D5C4E2024F7ACE5F6E327CBBAE1563C64975FD808648B267
+57B7FF03B1BD5593F52EAD3E595D3E85A7B9AFE10EB2BD6D787D52C0BFF0C457
+4116CCF971FF5F22FFB1024FF769895E29815F17C28B7CB8431BF3CBE155B03D
+C44E79D4C4E7E35039F148B7FA4E9A87C77182AC4331988339E75C1FD5669C70
+FCF70587309F57E3B78C65514339BDD15B2AA34BBF811A077D7E8934AF90933F
+97F756FEE92BE903E79F1E6BB0FE32F8A5CCA55C297B3091A171E3428A86B4C6
+83C908A4639B3C62663A381602FFC26B7B5ADD53412B22DF596611C7A6F2223E
+348447A4C6D59A79E35B0095A384B60C7139670ABFA34F2C6E3C6FD2556301FE
+4F81639E880398A8E1262EA015D130D94C499D276FB6720D3778EB3528442EC4
+6B5E5194EAE81B27F85C0698A8A3DC0BC930DFF2B8861121CC8EB6DCCD42FE6B
+4F93DEC21926DB179C7B12697883B6BED238FA532F0436A35D66582AC7A84C05
+0FD404C7F5BFA680285D4EF124B3EA4C72365EAC1CEE50DFFDFCA168B52E240A
+D020D8AAA3823BDB5B5657112783F8275389508E83EA84B88B89BB3C5D3AB188
+370ADC7530A31DEBFE2720706487DDEE12289B0E24222D7390F78AE4457A20C1
+50815ABF6C307C40D790DD668EF01EB5D6021DBE4FA8FA8A78227EFD3E3B0B7A
+026520B0788856B162DC3763E4224DCEFBE3017AB563C430EA4C649C8D32D73D
+5C960AE91A4A778E53FF136B2F1DAE45C48B3A99B52DD75930DD0CC565A41811
+48F2C3598F425631610F564349D3DB66306AD281051A2C7C48966D724DA6F715
+CD8C8D6E900FC3355525D960110AEF5591F8B28254B9606993020277D85C13D4
+E1E1F10FD0092A08B94D0D50334C044AF133B84BACCDD2C955721991229E8106
+0585D939E21539FE657A7A76F64D146D7457D17CE2A0445BDB6C185D4B3B052D
+4ABC81D4135D5F268DBA4259DEDEE96464AC15A526E6F29F99F8233E18E658BA
+905040FDFA76895DC1372FE3A4E04C524CFC0D3C33293BDC735A382A37DCEACA
+C6D00452DB9DEE563D955F2C8AC385934DB4E90686C04B7885F8949623D2449F
+6EDA0B985BFE44D1A9DDC475CA1F13FEEEA4B9B001614E44325595BA50110617
+35AE26253194D9D456DE030EA08AA398B7EB5153A527158889251310DB2402C9
+E5976DCE7F676B09ADDAB43FA4E9F1B497D31AFC6CE39F6D5E6F0AB328F63C8E
+A568BC3885866A0B67359CD4A8DC75A5D9B9C15D4DA7C9157B374DC46D06E86A
+09C3CA2016D3BD5A2B052A387BDB4B4F0D82C3F68A245855D415F8ADFCFBD327
+50CD63D609E698C6DBB78C6FC83DC60FCB5AAEBA38EA0F3DA6CC277244C76C8F
+FB5505666C0D7EB22968602134F7985B486330CD9E3231DFB5ADD4DA83AEAD0D
+8275235AB4FAB360B84B224A3C09E74B9AB16B1F53DABDAE08940A60ED0C1254
+DADC1CB72CFA17C4567838C313D9FB20D28088093BD3066F914F60F9B5C9C998
+C353E6EE80619CB44D4F14C33FC7980CB714FE80CF77BF1AC21947A39E5EA799
+B6563BEE8A7F3178C9576247A8C6D34CB084CCD110D637903079AD7115D549D5
+D2C7700391A2AF356E65C5268966CF36C0EC24FB19465D34068C8B52E18D2D5E
+856A34E6E428BCBD900CF6003EDE92E9C8C39EC4702BDA42B21668606E15D287
+2F75318F622364BCF0B7FA78481770743BC00FECAA671F7B9E4728421CA3961B
+EE2A5A39F1BFEDEEB81379D1E1051C25A3855A65BE5DB29B00A2A2E9011B5C19
+C767AB6D6AB8F4C472F365DF2459B48D596896E5B14A5FD33BEE895B8E9FF27F
+7CD6AEE3BA14F0ECFCD35C6F70157A95060E61BAC21DA35073F99409EF29FF7D
+04AEE73AFF5409B42F664CCD0C48A3380148244C23B1C87A9248A7261D50FEF7
+6795EFBC848997B444870A6A7012D59E02C699E191441D06880D7D946EC867FB
+38A8FC7A0BC46E6248E65E6FFBCB908E919EA5694B8405061133B2F19AF55A6A
+A7871172DE904F4623C5F9394E8914F173EFAA59912DF5CBF7EAD8427FEB267D
+497915C16B744A575428AB2C9A43FDCC0AD6BD9A1112E2F8D76B9DCC54DD110F
+A68B914F2DAABE310FA95BE489055AF8D1291DF1107B614FAF5A48AFD82EB0F6
+A662EBB941875D666B61C6745CB3D28B32397699279EA0AA49D62D724B6B041B
+B981EF79C0802D2883C816CAA52FA9F5A94E55CEFA031DEC3788E625DD5B1382
+2906B63C2B56C82BF192403287D99337C95749883EA18220DB2692F40FDB09BA
+2A58523D80230DF9DC3CDF7616D34C5327D252053B57E4831C81FB09EE450670
+289BF355FF46855B4DC2C2A9ED1FD973205FAB0DD7EB4A1CE8C7082613C194B9
+A69594CADC6F2B71C901450B706D916C548A7E09FB64C21C7E7905AE4003E533
+E05CCED6F23DA81AD48BA724A739C8EB94663A71E4AE5EC1108BA0C3139C16EE
+E56F28F3F394A799F0CB8FF2E740D2AC516C02293EE062CD063CA928B477BBCD
+1E2DFA98C99A0DC25CAE46F255CDB0FC678981BF19F04317F7FE4571C268BA9D
+A31E0821E183BDF3A043F263C9CACDAE461B1CA2B3FC55D24EA5CCE2C0C5FA4C
+EEF68B2C0EE9F69B2061B5B4F758D5075F77779C4543A856F7620745F29D71F1
+93A32505D54467EC581C635A7430BA296351F8D44A56DACA2105894A5FB1AEB9
+B2D157326A7F71003C6EC3802CF11DF323B847DE7D7030560E31B5413CA7DAFF
+1A17969D3C9278719ED826BF730ADC9DF64737B2BBF46F470BEB18F4B52A29C4
+15900BB7E845BC78A6D6BCAAD9B05C62C21AC3914E54721799414BA11D4BB40F
+C79B29830DE8E350FD105FC9828580C62AFD23476B502645CA83F29B1EC19509
+B6273AD95A48DF76743938B9E2D00DD0C1719C7C442D19CD783443146FA59AD5
+97018FE5719AD51E80BDA7113D84480D6970DEF24567991D4F492D2AEC3A095E
+0639D44674B2EAF1246F3A3E303FF2B13752E6E13CD456B24476075C76728B9D
+1552090B701B68E0403159E45646FD29A5C6D90F2B47DB998999549BBAD27099
+4CBD8884E5BED487BD252DB0F5673430AD279CE4DF33DA4554BEB667253C152F
+87043A6ED2EBFD1598983EAAB807658163F9255CE2B06FB1B4BE4C4DEF5DD970
+4B86C44F9BB4F001B81FC96487C8F098183877AE2D11F1E3E95D6C4177AFB9E7
+29D222D2AE4B367B0CBC99C136B169BAF121EEDDE32153D5B5E91EF1B1863B5A
+77D9843C6964851321957CBF79AC95F9AEB4208F57F95C20DA6E1AAFD2719DCF
+9ED3B35DD6824327609456107D27476BE90C44630C6516C86B089B33E2316A72
+918D5ABC5A103317374AA4ADA7B2A4D6878D5BBE65D9C7944856560B05BE7154
+806A0EDBD994D43EE7B64317BEA051AFEC63F754C3AD10596C8B7DF44B613E4D
+665F355F4E925BD3F472BF4347F07CBD53FFFBCC9CB3EB91A70CD383471A9CEE
+315ABCA987921A3DDABF5929234EFF02776D92043A5772E75C9F34B9FB963642
+E9829993651DC23C9920F3062284EDD73A1903BBCC7970CF7C73107876B23B95
+87165CD429D5FEECCA3604B342F52F2354135EDBD61F72E44B1EFE66C4AEBDB7
+8D1396624279B6C79E8496742DD7A6AF9C02DFD4EAEE12ED7C9B6D4958A4B249
+9A7118C7EFFBA274A9569891B46DD0D3CDBC4C9D2B4CC72C641A24CE48708D21
+7722D044F801DE0E656B921751A3D60DD7F9229AC79C3715A2E44BA32A73E57F
+259092AC8E10CF35E239F272B8466E17D9738B55CB9C64A8DE2AA60AA95F7454
+0F29A380D4E735BCD50D3EF5BC74720A900E45840AE0EFBCD625F1BF8C784E82
+C896C1762E9DAB2965276F32DCEF063C6F64709284BBD1E4AF6E5D399C423302
+58B780F6A32E20E04E03FD959180D6DF0FC6982D0100CE4194FC3C345011E0E2
+6860DFB77B5E3067AEC5EBAE0AF4639F8F5F3E8E8722B6F734C1AAE6107B673E
+5E033E584C9A9A0B8BEE57E186E1AD27963DF9632A331327F125896E7E9803FB
+5FAD92FC6817B00B4E6DF907F82930782DBCFC9EDDD068471915AC7F7CC71877
+13023744C8CA717AAE350564E617B4DB858FAB9226A87874FCC226C2C0EAA971
+1FBB9ABE5FB5B4D5871FBA18787DCEE2998400F921566CD6C973C28C11C31D25
+1E1124939FE891037BFC37FEC0CABE8F844318EAE1D440687F45045E0767E18C
+500CDE3638733035FA968CEB5D2382F40C64D01403D77597069F5FEE8C51EEBF
+2857DF09D89A33BB5E144524BAD6A793796650CBE101D82B2D44D17ECB9B15D5
+9CBDA1644868CF80A1BDFCCC7B2D3A8CA94AF695916204CE74B44975CCAF8006
+91A6FC73F8116645AC29180E43261236832E3F6AB757E39149BF0F47D148308C
+284B50B0A8270B6220CF99203FF58E2D81CD5956C1DF67CF3B0B03033F07DA60
+771C11EDF277DFBA346E60B0122C659D8BCD1F7FCF3850972487C3D4A5ED6D96
+33F8DBED21E07F478B3C1F2324330599EB6570D0A5392C0387B21BCA8197C258
+1725F14551ACDEDB213AEEA9357BA9A8AA1280406B8FCE04D1D7F4C8FF8CA79B
+207C56D9641624C54BD75A384F9FB7FF0B12C534FBD0B30B29AFDC8BD1FCB465
+065BBFD6C41521E9D542FD57F6C37914CB27CA8FD99A6F6DCFF9809B7CBC5540
+89C527E0ED1DE3A3828C7DF788D412C0065EA9599EB8C400D3DEBD8B52D5886A
+8BA648163E2BE838E522E7265BD101058B47B85C6B5196EEED9D26435E3797BB
+B9659BECB66CC4DD4BEC03B393BD825A0919566D8E4446C21207C3030F9E3574
+A492FE5E2CA3B1F01253413EF8180BA2F53F7E978F41EBA2C7AC61353E71F3CC
+9E4AF0BBA32846567A27F7BBE11D29D48FA8938E04A802A2C231C9EFC761F826
+D889E0425CCF0889490B2C0014E4AD7764905290084EABB39E50274F5EBE180D
+C62349CB820CE7E3577430C01C322C044152FCB5F7CC786755B992D2E3ACBC9A
+8A592AD0266B0391576BFAA177A32123E633638575986048F093975E50611C9C
+930882643B12B6E13C2EFBF9BF582A539AABBDA7CBCA4B3CDFAA70B0AEBD7D92
+25B94EFFFB52F5E7917F93816E80DDED78CE01F93702587936B585D21B6D08F9
+A14443C0F9CA4F106D35B296B5B3818248389381BDFED56A8C7E1A3F26E14937
+718C587DFD611CC547B8BDC2126CB8BFC6193BD14D0E0BC0C325F75049647AEF
+EE4277382899C8A2E08B603AC686F6F5ACF2BDAB6665F7F0D7F179822C7B6386
+9670A5D8E57568EBA3C024B845A12C8C8E7065F92F34A3167A0E436CB22F4200
+621B558813CBB8E2EE2AD842CAFF4830E587634344B0B55FEF1DBAD0AC5891DD
+8AF6F0DB42E2ACC4254FB9A5A34C7F72CF9259C0B72F4772F18F722B1A28B18F
+BF01757EF7D210D2FB0678B5BBAF2C73194C94A06A2A31C4CFDE6B825E474AE9
+EB2B1F87A18E659E9CBE882076271C83A823D671748DE7780184426F20D997B9
+1EF4305D74C2350462820FB57B7A5CF5B5114EE771491149CF01EF5C5DF73B97
+BF1D27BA0F9CC59F2FF3DC7D8FF34B6F39A6ED770F9402D0C4FB5B8655AE9BA2
+DFAB14DFBE3420F9E3D7C612BD5B339B2B5E6EEF02D98209C836A4E20E1F927F
+055261228D83DCB2F61393FB34CE5191645D09EE0DD03C70E6B07D3083A38181
+30CE3DB58B9BA3922A9EE272060C2F1275DC2B902673798B6AF8F481B6C89299
+996B69D32AA1EA559BC0E8EA45DC6D0674D505C8B8460FFC5FDB5D9CDC59433B
+A49321478C0AD3C52A5DBE6C60B565FBD1A121BD223BB21AFA0D138E0970C793
+3C9699791E9F4DADB833EA67766D8D6C185719A5EA284CBDA1A740B00DCAECC5
+8C34515236F6FF7C3D579263468986FE19577777BFB1109F398EF749CB223404
+75A0E3146C5DE422F09B89A8818DDE7A202F5F0F77BE91B1B5A77DEEBD312A30
+377DE334CD5B0D45F65123E722DEB09F67EBE17F8794BD7BB239A2ED9F68C024
+FD46810FBC33965DB3AA59C8D45A247D8611EC7DB4242C64E7DF74A5036250BF
+675A3EFBC57BA3B045E9EE219E5740A2F42F6A97849C847FECFABC10D08612CC
+9F9D369F2811E3F83E526BF5DC45AF2138146FEC19B1A1D55431FC1D1E9C2A54
+79A56A473B4BDCC9D349F3550F8398E411E23B28CA187AA9185F70FB41CCA800
+72C7D018FB807132C678575F9EEB429537ADCDBE901C5BCDCB02C8536E2E4DC5
+FF7779D13B00D7FC14509DBDD73CE400E71892028DF6E0F6873F8C5470C4E189
+DB0CF99138158B3A434D678AC518357980944C83EA57922E05BE21B5C6EE15BA
+AABB7032B4E5265FAF9568A2D625E6FBD3AA735F56D3E0861D187F487C1D43DC
+5893D8AD8DBEDAD725F0B27823D212DA832EB5B1B9DB09960CADE299AFC1C288
+DD42E6CBAC72AFE3B901B5ECE04AA60025142717E0BAA99EA46CABF138E1D537
+B870D2C54DA448BFE1A52F7F65838EC14E194AC3318045566983CBD9A623D211
+5E00EC7A016F44F9F6F01995CD6F29D1F0EF5055DED50269E4959FFDC6A431B5
+C368DE86301C8F11D22269A1CC17FA32F2DF75E25BE046ED84A8EFD316B5C837
+A8751E59908AFCDAA287A5F3207C4962F834863F9324034ECE5E52E853B03D4C
+555C068676DC506FA61692CC611409D6E391D47003CEF855614C8BE747CFF0D3
+F812DD4D00CA4808E6181F48C47BF05669A7BF6FFB8086A15400DD7DE5504907
+8E986ACB7E6BC1D7527C07C183FBD67770819DBDAACD2A42F92383891B1308A8
+0ECEAA7CBF251FB093463E5E04073D11CE549445BDA44B899136658907809B09
+F982DFE90E838F7DAF616A149920084EAD2631A70FFAE1D79355CC1ED7471671
+9F9443CF76633EBF302D8FF5A52FAC37739647FFC0BDE2253B78A4D3FB1B4516
+45F6E3939D0AAE2D7C58265FEF253958230A392F6A3F0EC15A86725BFCC3CD4D
+04D987D92532A34DE1D5EA52C3DB52467D0EF321F7482DA56F5510DCD2E4530B
+BE8B241AA58E45C66C491184C2BF9E7DB86DDE442BA31A23F9051E94B6BE2FB9
+C50645AC4424D9DEB70EF3AA31A629238B51B0AEF2671BA206F996002BD41EF9
+975C6339C00FCDC2069F8199BB2999CDE805B144DFAEA00BC593E2751C6CA957
+5095DB3B3F07431FABD85675A1933F416D60DD31BC70E50721B5D9AF5D36593B
+4E42DB695B6BAE14DC1A34B480731D0AB8DAAFC7AF10F9A1F8E16D757BED3DDD
+62AA54B68463A1B4FA1D2349AD8C6B581B52373C444FC9FC57CD5903C76BF3EA
+C052B511D96A620A11D6533093483ABD264E795B7B2B2773C1DFB8B412E3D8B9
+AB3BDC5ACCEFAC42B1ADEA8C534EF7020860FA9A63BB9E3ED8B4AC4D5221F795
+66F9ABE68CE5F160F2F4A7E247CCEDA43BBC2FDDE31FE7A2B4EC56C294E42D11
+EC3E75166A0486F7B8652F2BBA9C3856A20BA4C2FDB58EF7C4ABD9EC4312C5F5
+A41566EB5611FF52FFE11DF40218EB1FE8C13B0FC8149CC417AB2029E3CB9B52
+79B55459A2EDC81AEF8EB54D13F8235607B5105F4EA77D49589629EF70A8D5D1
+BBD7836D5C402476D1AFB6E196A89BB3F7AEA1597792D37D370F4BC19EEA41EA
+00D9B2ABEE8EDA8641DB1AC5AE2FD29C208D1A0ADB4C465E3A8A5EAE18544697
+04279C6A0D5D93E408BE2CCE8D75FE2A35CFB8D7B4F9AC5424723A38E7D8F37C
+16C8B712A7EF6CE4E27D6E2E9DDB6D41C9E7289388BED91FDAF09CF6C9BE401F
+94D39963A38A5EEC4C937026170E0EE9271C9549F19FDADD2DF72B13A00D7A8A
+44BC326794CE776AF89CBD474A645947FBFB29EC431E9DFE81370F3ECF9A848E
+E31FD0F505D86928C3FB81380B7EF2E4592442455041810157FAE45BE7280CD3
+6DB6A062213220A520C146CB60D1135BBA697B789C98640585AC0876EEB9010F
+A1415719E0C652604A118B54F7C629DD8B881D71756F3701002A469D62B23279
+B94E3E63A62B10EFC7190F9961F37CCDF48B36275B0CFE086E341287610BAEBF
+8C8FEDB5E28BFB3BA6EB6EE3F1052CDBCA9014F0D7ECB292F44D4427BEA3F39C
+6A432213F7658B4FC0E2D78A98DD30927664D1EB4F2BD071B73938AF86B5F52A
+2452415DA9B20C472C6A28B0A0B3ED925AA20E8009EB21C158FC2B1EE3AF3DBB
+CD24F94211A8A93C9F2EB74C46353E60D0AA8AFB5E428324481A9DA336B021BA
+28891331E6FE0254CEB6706A193106D5CFBAD1A8EA4F7BF13DEAA63DE0F48533
+4DDFFC0B14764FB2DD3397D0E3F39DCFA3396AA1922C08EE331B2B758C83EF4A
+5E9C39CD869AE5545817F70BF0FD41C047B635CC5D5592C6BDC563D3214CD19C
+F926EE1F1817C88BA1370C72FACCA14AE14EA0517D9500BD0E5ED727CF0BBFEF
+BB314830AB7A3F4C0E3814711A67E4E3952ACA56FF20548566012E24B02C7CCF
+DD70718413FD054C4FC92B390B4424930CB273106DDD53B736B894619D9D200E
+CDE1B27CD05D4BE4F935C5F3DDEB4C9CC9BFBAF603ADE044824476230DBB51C7
+83E37262D67D9470A064DBE4AF8E4262CF2B43ED064D86502C05DEA86EE9E1A5
+A4142870B680AD40258204BCBD6728509E15F78FAB2BBECB5D571FC630F1DEC0
+A8A341B7E330C9A0053A166BE474E8CBCAD139FFAB6EFF4938C98CADF2B6B64C
+EAA37E9A72C0321EEEA55B35906B957C3C2511FF2000DD33BB7C9C58DE3E4F82
+4EC7E2A0F2E272305AA0EFAB70C545B5B3B7C9B7C2D2F52F2C9DA8C099E7CFAC
+B101EE39D0D65C89689646EC6B74055D0F6CBDDB1F7A53895FEF5353706726BB
+586FC64B77AC5C3AB5CC581D58E8627910497562D277879CBFC3156438144CFB
+97D28D067C73207C30F101210FDB2E0B6097D435FD2197B1AEA0DAFAD83B786C
+735762234838EA2FFA35C39F367982A19DDF17F5ED297DBF970B9FF0043586F6
+7BE81E18A34252B718F1EEFF2BCC9232D355C7F5D154F48BF7BA9AC0787B2750
+E5C1E646D8266153C44DF306B130809EC984DF94A2D0554B6CECD04D7ED6BDA7
+72A56328F0390CFBBE36B2580AA83E6987D26AE4C58123088CAAD46E25D55CB8
+FBFBA3CCAAB74958A4F40F0A608574013C70B4C2730B1CC8298E2F40981E48C4
+6408E167D696237F9899C84F1EE227C371982652CEBF0EAC169BECC25AD7EA3C
+ABF0F7B5A14674D9DC0F8159E57DB19E31964FA8D2646F514DB963B22240DDC3
+51C3399785F8153CE5FBB6D499E97BECF1A24F0FA1210EC51CC5F2042FD09317
+EF5E641E17C501309AC0BFB11700CCC7740A59A8D2BA6D7A9A414273A3C98A07
+B9419BD6F9DE4E85381BF876276D2C13A73E81488D856BFEF9DF4593106B0D51
+D4665CA073BBDCD3D4F301954E46DC913DE49A9EBBA24F0CB075A282B0DFAE50
+6C18914EC448E3DAF27D2DB066626D47497FD893E324B468F2A13BD6E814EB07
+8323C7C2AA87071251B909FFFB5DCA4E1B892297D765788F4E938A52D205FC10
+C55C0A3B6DAF8D3133F46117D9E71C8CB16A6D981AA84393D852BFB5FADC5D5E
+8CB2B91EA1530116F9C81FF31E4F3A20197CAAB7279F0568EFBA2EE67F933338
+789C24BA3E74DDAFCDF6F01A8ACA489715C0EEFA0FDC5A826B38342FCBA7025F
+3EAC9F6C65BBC6753BFB4F7D300020F90195BAB56722889792199ACD4494EBA2
+72A36829572DF2C72EF2E61F95D603B80491832B3E8C8D8EA2E6A71B5F00F7C7
+574A3C863612630323732596044F042BB94710672E1069D0157840363AEF8F1E
+D480693DF69F705A3CD64A700650F61182B36A95DC4877B12C37E2268DF855CA
+2538FBD173F362C8BBC7C33AAF04A6E9A882CDF6F950D12DF7F04D4985940CDD
+60F7B5225328E63228D4316DA03B1F4819EB374565B51DF1073AF7ABF0AF43A7
+98C8245758C942D45BD8D59BCF0E833ADF180470D3ACDF163AC926ED7FDA99C8
+450D986A7C7433A25D5970787F13D820A6199D8453059D59E4F381530574E1E5
+8A72986FACD57CEA0719DB404BAA0FA0EC5A707206B8F68226B081173D52D61E
+9E1D33FCB54D826CC4C1517D5C4E8661A6EAD9C8785ABEFDBEEC616C588F0C96
+822CDF5F15C7C32CF4E3594EC06F129AE00E92E84862E8F89220D34E99C610B8
+FB97FE59471F86749AA569BC8D13B17614E019F16EEBC6FA52A0D5717F305D8B
+C4B5624A7C448FB7E603DEF678B3C2727D101243454CD0482C6FD5B1C8C7A339
+CA270A5936B1C9AAA00C8DBFE3A35DB168DE88157ED9B4AF8D8EF9884A4AE6A4
+61CB141C9753C039B3F805CA4C0DA2BC23D6072AB95C73F68C5C043B791E00BE
+3F307EEFFE7425317DF44936E16A28DFA3D29DD391BFEC352A77C1B5596D2A5E
+E59AE2D3FE0008FAC30A19694F41A491E50994756E0422B7D911146896D1128D
+B0C51AA29A40DF79781BFC9B65AEC8AC9F8D5ABA6623096E8FA6E500B7FA183D
+475001CDE84C6F37DF6CBCD0587BBD40F91052324CD82D3167704B77E4AB7CB7
+23D65748640420B3512A97A3F2BA94AE5CDA4F354A7D1F4B4602D5B287CFF92B
+89989D5FB7BCF6E90FF511A33CC436146A90C05575EE1D83EBBC87CA4099D15C
+EC51034C4965AED230A9C17A9AC20FE1CDBAE57B5D2910941A03315D2826C8FC
+8C5A04C1D601EABDCED9B77B9977F3B78C6A43AD8E38681F64832C22AA0B2584
+46A86A6D1889446C6AC4E04AE220274D1FC389A68CFB19801FCD07F99943112B
+A67CD3AA77D6D51DF9E4D87D86A722C0F5F1FB88EFA80DEDCE56F1CE41600A41
+FFACECFD8EF1D33831FF44C120A52D0D6014D9BEF28D2DB07AB166BD091BA956
+AB54D02410632D892EE7FC47660740A4FE92D7CE736FA5F80D1B6E1267D7801A
+67AB4DAD9F30D061E3DFB67B6FABF4B3BAE9D65C6F78B379B3C9C29E838B569D
+D74A3B4C01A5857C61EE3AF17E89DDF576746843B3C4A3663E59170D9BA20892
+BE4106C1ED10F127373B6010A99B148A7EBA061FD9F9423CA8FC89AA0AE434D4
+BFD47987917E1BE0E78B61759C635CC812877047009DD777315B67A6A319A12F
+9F77928E2D76C191B49ACCECB996584FD390DA101B4E4FE25DA8CE592A90C71F
+FB7D10B954CD8BC8C79EC06D5EC1507D096C83A4BE59403C1B47294F62223AB9
+B398A6A9171269D7B540C50927159791060EBD9313B28B63A2B1BBA724D9E13E
+AD00F85DD841D5FABE1D74F94A7AAEB1DFD291AD6FDFE21BABDFC105F3DFB700
+89C119DB049F7D16B616BDEDD6486A2FF06F32036BF0B5DD79B3A01B4EA3A53E
+914A237B0F1C41BAFA69CD5B914DAE06B9F3EAC7D558878A5454CFBE2D38525B
+253CF5C058F661C67A652DDBC984A68F4DD866EC683DA31EBFAD03EE80BA7091
+01438BD3A3F8C65064BC3AC98909D6979A515B572FB0517CE383A154C90C430C
+E06768A3F6566C043B8605AC5DF1562B788A411FE73F5C5D11564934D4471019
+0C515D6198569C88D3CBB7A72111D09C5DC5FF3F50BB84CE196652BD1FF3D97D
+95E9C715EF9A3BF183D16C275572467A02A4B1CCFFAB98EB4C1F914C7800DA51
+52565CF08B3BDB3277851C966A14D9E9328E4D78F11FECAF8E71B6A3684A0282
+BDA7C8BA0FEA41162E2114F63E78B7E596FB6D545F77D904B2D9B32A0F666C26
+0186C4375B079F29372CB394082F5A43E137C096D1A599DE985FC5CD47C18C41
+7021800451593B50D8CA08739801C5535C4E3264E6CADA9CFBA4B05987C21F15
+F81AAE21DC8C9B437F53C90F92483E1CCA54F924EE5EA259B261FEB009292CDD
+5C355B84449B4AC913B4FCD5EB71A8D3EE7D77952562878C5166A1C9E4FF22FC
+167DE9CD2179B69AAB8B0AA9CEF53B792315CBAEC0D513B5FAE89323A5CADC6A
+2B32859C5281D6A740A36CC63FFAFA1255E55A9895A76CB7CF71F432E49956C4
+FABC749C776B3B8C6A03FE0588339798B41F8F5E484A58263236E6186652653A
+B2D7735ECDBA6DE201856DE24C2F4BCC42CD9D51F6F42FA283909FBC9063D619
+B9B257089A9327E438FFCCD4AC70F59068D26FBE8B8EE6E788C6AB9E7E29203F
+9DFD3525AF79025F16E5DA7D94BA86F2143A7157F6A03D70571CBA724A0D2BCA
+F2AB22B9FBC1A20594D0C9FA7F49CBB3A629A548886AB3845DE4434FD9A4EA01
+83C5C78F5330426DDAB35B4FD402012C0B05C2FD3673151384BFDA297FEF8E74
+54DC6742A24756E1FDC69B9D7E5A961A16093EE4AB04DD4B877497D7A8144A2C
+3A80501705CDA7877D1D50B8EE2B2C97549AE0AEBDA9F4352E1B6BF512D5B6A0
+CEC79DC26443A400CA3DA85D1D038C176E67241C6983080E7ADDC7806DC058DA
+FEDFCA543A07A625B1CA963C9578BD5DEC6FFB468852C545EC4904B01BBEAA4B
+E6CEC3D395091573260867CA11D0E04301B94C80B9EEA7B160B9667BDC2E2761
+CBC3B87D3E8E0A409B3763BF2788ABED367483E68E4D37BA44752631B106D8A7
+4760921ED93EB618E188FE8DE96C3D9152D7CE8492C3B9A044A812DA092ACCA3
+1DFA29C59E39C5384548A7C9B6F2F91BFDE6C35EC1A969C3A4ED066F40510574
+94F25777B103A1E7ADBBDF8E09F174FAEE2909D52AF5F1DC7CB3FB0659BEDB3A
+B99D62939070E00570CD6EF89C4687F536BB72FE7AB0FF741833BB0A60E6BE13
+E1C5DC0FD20420877FD4C39412DCB19E738D6D405A03C568F82BC72EE475A482
+FD6A8D6EF13997AD8643B84F46CBAF446A1EA1653F40CFAF3843A03E010FD3AE
+FD09AB97CB5016589A9812814A4A6EA108332D569FE4854765CC72C161D64B8A
+E14971088EFD968C0BDAC607137FC3C7B1438D2EAA3E12A7923250989F6192AB
+B712B2A90F3CA5A9EF3747769E16AE7BE14D08688BC96002CC2AEF87A67E0AAD
+4F12C061F097B736D464AA0CD842C792C1EA19D37D243B675FC3484C1707BEDC
+B2C46B0EFFADCCC9F6A9C9DEDC2970DBF831FC1C99B0F108BFEDC284F64FA5DA
+628691BED049FAA82F7DEF60C3C975A452D75D49B36F3159219E26D0984EE42C
+5DBDF0853A101F4D2835F315C64F727838A75B13DF8103578BE466015EF7ECC5
+0700522F94EE04C0253BAFF927B3DF27E641AB961ED9454A4304F87BD22D6C49
+21707DF91D903F3C68ECA78721E77F26099A10C303DD6FDF636AD9FD1E648584
+5A5ADE21B279028054EC9085A18C9DE16B8E263BBF3CCDB15D4DF0CF2ADA4236
+3FC37A4CCC959B5502247D2652B231BF0B4604041509DE8CF5D59B58224A4FA9
+B322420A266B2EEABDCB846C9162D4B490E0EEC0E21C3FFB978754976F8F3F44
+8600BB14B959D50E0A3C729431567F825BF7B8372061B3C96CBA50A4A3132C06
+1CD2AF617180B9EF00DE426E23800F6C452F9DEAE99B4587CABFFF621A6EF786
+5D423A8415A250A7B676DB846A31524A783A407988C79414C7A6855FB35F04DC
+EAE0D9F9C559D60A1C16E41825B80FD203A7816E4F93991DB0C2A1D45548443C
+642D7BC114E133DD21628F4E455A4905127CC85965A4CB2896B713570AB76B57
+BA46D1C9914D5E90B9908F72CCEF290418B00EC22794619A951D4513DEABD376
+D80B71669B683D8BAFF3A86487F8F83B77379CE0C1356F16DBE8468B05B5A4DD
+8A8A3FAE67
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+%%EndFont
+%%BeginFont: cmcsc9
+% T1FMT-V2.0, Copyright (c) 1993,1994, Basil K. Malyshev. All rights reserved.
+12 dict begin
+/FontInfo 13 dict dup begin
+ /version (1.1/12-Nov-94) readonly def
+ /Notice (Copyright \(C\) 1994, Basil K. Malyshev. All Rights Reserved.\012BaKoMa Fonts Collection, Level-B.) readonly def
+ /FullName (cmcsc9) readonly def
+ /FamilyName (cmcsc9) readonly def
+ /Weight (Regular) readonly def
+ /ItalicAngle 0 def
+ /isFixedPitch false def
+ /UnderlinePosition -133 def
+ /UnderlineThickness 20 def
+ /XHeight 526 def
+ /Ascender 694 def
+ /Descender -194 def
+ /CapHeight 683 def
+end readonly def
+/FontName /cmcsc9 def
+/Encoding 256 array
+0 1 255 {1 index exch /.notdef put} for
+dup 32 /space put
+dup 33 /exclam put
+dup 34 /quotedblright put
+dup 35 /numbersign put
+dup 36 /dollar put
+dup 37 /percent put
+dup 38 /ampersand put
+dup 39 /quoteright put
+dup 40 /parenleft put
+dup 41 /parenright put
+dup 42 /asterisk put
+dup 43 /plus put
+dup 44 /comma put
+dup 45 /hyphen put
+dup 46 /period put
+dup 47 /slash put
+dup 48 /zero put
+dup 49 /one put
+dup 50 /two put
+dup 51 /three put
+dup 52 /four put
+dup 53 /five put
+dup 54 /six put
+dup 55 /seven put
+dup 56 /eight put
+dup 57 /nine put
+dup 58 /colon put
+dup 59 /semicolon put
+dup 60 /less put
+dup 61 /equal put
+dup 62 /greater put
+dup 63 /question put
+dup 64 /at put
+dup 65 /A put
+dup 66 /B put
+dup 67 /C put
+dup 68 /D put
+dup 69 /E put
+dup 70 /F put
+dup 71 /G put
+dup 72 /H put
+dup 73 /I put
+dup 74 /J put
+dup 75 /K put
+dup 76 /L put
+dup 77 /M put
+dup 78 /N put
+dup 79 /O put
+dup 80 /P put
+dup 81 /Q put
+dup 82 /R put
+dup 83 /S put
+dup 84 /T put
+dup 85 /U put
+dup 86 /V put
+dup 87 /W put
+dup 88 /X put
+dup 89 /Y put
+dup 90 /Z put
+dup 91 /bracketleft put
+dup 92 /quotedblleft put
+dup 93 /bracketright put
+dup 94 /circumflex put
+dup 95 /dotaccent put
+dup 96 /quoteleft put
+dup 97 /a put
+dup 98 /b put
+dup 99 /c put
+dup 100 /d put
+dup 101 /e put
+dup 102 /f put
+dup 103 /g put
+dup 104 /h put
+dup 105 /i put
+dup 106 /j put
+dup 107 /k put
+dup 108 /l put
+dup 109 /m put
+dup 110 /n put
+dup 111 /o put
+dup 112 /p put
+dup 113 /q put
+dup 114 /r put
+dup 115 /s put
+dup 116 /t put
+dup 117 /u put
+dup 118 /v put
+dup 119 /w put
+dup 120 /x put
+dup 121 /y put
+dup 122 /z put
+dup 123 /endash put
+dup 124 /emdash put
+dup 125 /hungarumlaut put
+dup 126 /tilde put
+dup 160 /space put
+dup 161 /Gamma put
+dup 162 /Delta put
+dup 163 /Theta put
+dup 164 /Lambda put
+dup 165 /Xi put
+dup 166 /Pi put
+dup 167 /Sigma put
+dup 168 /Upsilon put
+dup 169 /Phi put
+dup 170 /Psi put
+dup 173 /Omega put
+dup 174 /arrowup put
+dup 175 /arrowdown put
+dup 176 /quotesingle put
+dup 177 /exclamdown put
+dup 178 /questiondown put
+dup 179 /dotlessi put
+dup 180 /dotlessj put
+dup 181 /grave put
+dup 182 /acute put
+dup 183 /caron put
+dup 184 /breve put
+dup 185 /macron put
+dup 186 /ring put
+dup 187 /cedilla put
+dup 188 /germandbls put
+dup 189 /ae put
+dup 190 /oe put
+dup 191 /oslash put
+dup 192 /AE put
+dup 193 /OE put
+dup 194 /Oslash put
+dup 195 /suppress put
+dup 196 /dieresis put
+dup dup 161 10 getinterval 0 exch putinterval dup dup 173 23 getinterval 10 exch putinterval dup dup 127 exch 196 get put readonly def
+/PaintType 0 def
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0] readonly def
+/FontBBox [0 -251 1076 750] readonly def
+/UniqueID 4701553 def
+/StrokeWidth 0 def
+currentdict end
+currentfile eexec
+9B9C0887DB83FB1ECD8335B0BB39CEF0AF64F656FC6E5C230CC9D3A7346AAC7A
+06BD9A40393CA15D3773A21E06B9B4254D3050E90726BBB09120935A8D448CDB
+C799D90205A21291254FA633CC0C2ED88781EF21A5D45B72445C284FA44F8F39
+CF566976075A92E9E2947A6FC93D879C29EB26809ECB4409CBC8666526CCED92
+65DE661A2F8B0A16BE45A9DA17EEAF89B0E023DE2B0373DCAB997D60B7D7DC1B
+4F7E650A2A9F13CA0543F3B080AE33D65F2802B8C5214D5B6180CD886ECCD253
+99CC16C5BA51CD8C2F5943EF3B7FEBBC41F6951EBBB60991342E76B6E286261D
+E282B144F558FC13E776427AF8A7B2589A50121C4E28CFD74A2F2AAD8F44B6CC
+8D2FC6C09B196FF2F3B57580F2D92F0ACD7DDE415F2830567CE4B6560BE25202
+D9D4886AF231510823457D00E29D865CAEEE2F697EFF80BB5BFF89DB01218A17
+F1FE570DD273492DB3AF7ACF86529ADABBE036A7437E7CA91DCB2E644C563D67
+0EF57503EEE64158B375AC18F3039284C1E3A18EFA72C0FF89FB1648F8ED3984
+C8D3862EC8C644C3EAB25B86127E6DC4399F9A9AB476B5E5A534E17E1118B4C4
+3D135A1207A11ABB75446E7003B42FAEDCF12EB2C53850AEAF1BD0A4041FB4E4
+0DA8565C86E80AC45F75F52779133381BF75A036572BFCD7E4576B1BF7F62C5B
+FB1652CA0DF458AD89456F5F941CF4BC558CBE68D17F1EC76BE523EF2708DA7F
+5FA9663586861AC907752524F88C1BC49F115BA3D24D0D7572A0344F761A7E29
+37E137614460C6BADF3720A004E277E7A0A618ED0D58C38A0EB68AAA09CBB481
+3C9E2073A5D5D38FDD0A31E3CB2399AD9DA6FC16CBA9A6792D02982A2C390398
+8D4AC5E33E7E91662D06AEA787ED73A95D7FA1112D074686F4DC2DC754D7C84A
+4640F61821067DE9C04E4E431300D7347C2E8161C050DCC61F298437A0F95A77
+19D1606BA794F6EFE48A250174C266746411C4603B4CA9CAFC536D180F40ED24
+3B45A3FE2501AA662247145ECF864EBFBF8D0A08DA4940F4EC99EC3CE2789A73
+259C061EDA69AE360BF94588A0165315DCF3FD644E74A6CCFE477C2D422D4C7F
+237E8FEAE77A96BC99C160B54EF4BED62AAB709007664BA919686F4415D1CA02
+1F0D4BCBA91257E1EDBC90496DDFB478109EF36B0363363064461028D2BC8DFA
+013D2DBA456B2809A488595590BA5738A7FD971FDF2F5D20B33BBF008B957D63
+C4B0506DB39F0C609802C6F7AFDEE93383BC960FFAEB5713C8ED2459FC4A855F
+8B57EA91CE30F65D1872AFBB811F3D9BD15732641AA0CE1206D8CEE3DDB0F2A0
+708A56802B0C5B375AFA45610C507D5393E9C627D728340DB00D37EEB59E1427
+3EC105AD1D5CB55F5C1A77B2CF839C857AB62998C6CCBA2614614373A1B8F1C6
+F77D706B3FDF49B0C40E292B40B113724184BB36B8BD2A0F6866A34DCA624228
+189F6C161F80208C85CB721AD37B4ADF8E9669149B5D4B3CA903B4AF073B8749
+DA249AF5E7D2B421954F5BEC85E7750025D592CA10B7F10FAB381D7CF988AF29
+5C5AA2AFDC912CB95827D0A4BB558399ABA21ACAAAF7C829B25DCAA9DC5A8D54
+EEE83F52514C59DDF8E0CD72AAFE759520385BDFB077BB65BD91EEBEC28F21C9
+A74EE3917466D6EC4EEF2112259792B429BB0DCFFBA39690027620EE62BC8122
+676389EFB15385AA00B7A163CF872254C315805D34B4F2F2FF3ECACE5457D66F
+FFC2B68E45D8AE5B7AA8F8BA683A485DDCC20BCBEAD17A058514C887172C9811
+F2848607636A78C4C061815F523AEFAE128910D3A1368A56C1590D63DBA8DB95
+4A057427D5F676D96174A8251034A396F5A23FCA205A4FD1A221DC2E8A652A57
+957F6F91AAB9A1A498DAED793244971396903D8F2640A68E4799F6B65314B714
+6954C59C1CAD073C968FA30522FB0BC9384BF02BE6446A0F924A133AA4651F5F
+78AE452288AB82E6BAC74C269001C3C84F3F2A8AC186C94D78529218CE820484
+AF9630B17ADC5A9D775DE51FB915265B6A1E5BB85B8C798FDB6FE8A6B6F8BDED
+B587380049A581A4F39CC45B1F4A5D686018E627ADCEE4F9F670361C6F708E1D
+B6F8A95DCC1048EEA22E28E0C311A394A9AEEE405320400A8B2B0A615E2B36E8
+A177871AABD0895C92BF702527576A3491BF02229B28F89BF837FD36955EF049
+FB8C0AA830E7A86678A69A87383F10715BD1494482034ADA7198A1B1A897D32F
+811B500CD638E3FFAC6EDD67052C3CD2F3B11CFAB8C804FFE72DC4E55138B701
+BFDBD227A50C355B07689A3BB3B6BDE072DE9F98FF0352434FB04DCCC619AA17
+127C0DCC6244BD9086EDDBA102D5C67610004657570182F7900878C8877537C4
+58B1E0FEDBE52F4671BF057B897B8C17AA1D8FA79B8DF2DEC5FB4CED9753E8FA
+C5494FFED4283833B2F92A94D7890AE116E99D75BAF8C78C4C2CF45482571064
+E9E589D7C5E195BE5C2C391AED066CE4F180000006312E6AF84BBF6388AC006E
+EB97A12F239140BDCB4B782FFA4EC629C1BAF71C61AF96CA5278F83B9609A86C
+83774F66C3FEF89CF200092982A44C1B882B8F50F1778639F6C1AE966B2B36EA
+1CE494AD85A64F52CC6C9532DEDF57843A4282EB59EFB7FE94927EC7598EA30F
+8F6A2D0F916C1DA7757CEA370EE057967220E61474C71D1CEFD958F816F0991A
+7747B0AD5EB94D31030172C36518DEDED362753FF1C79B4F08247F6567E2614C
+F390AE7B78FFCE142077F01BB297B89C655AF5E6CF89B22B42B975F7A6CFA3B4
+17E90FD3F71AABD1955905A37C66F94141285398FB31AC9BAB1A1135DF1F9748
+247734D6BA8F945D8ACB8FBBD8C879D23D31E216662D16A3CC3AF875C96A39B3
+EE96904DD2E49534791D1772796FCA4129D97E9DBF14D8840261561EF1FBF602
+9966CE0B30FD010B07026B7ACD566D374220ACA7BC884595F95DAEE27A818849
+810982488090BAAED7F0B768417E510BADFD4ADB569FA3C879A5AA8474B600DA
+FD7F986BE65759614BFDD55645B11D66378C490BAB8FD660E27E5B3762D9C0B9
+235D771CC51207FACADED47894F0AE075E3696214C9FB7F2456260B5FB02155E
+C724F5C00CCF06892F076C90DDD6378DF26AC341EF6E54AFF0DACBDB989406BF
+E43BCA29754B6BB39158142624DFBF332337F2B100FABF6CBC8EA7FEBF987145
+767CA5532273E7AABBD4678596FE8E0C4073DB776C16E0D28F941D0C0EB1019A
+F6D14DC0F67CDEFC136FF2379DD5684AF943D9F75734496F42E1E58AA9EA2EF0
+B767A58726A5E5E3A7A8EB1068A0EF9A2CBFD99064A1E5066006D70046BD5BFF
+AE8E7392ADEEC401E99610ECA89C3BEE5AB4FFC1B9D1EEAD033F049CD50B2DDA
+499192D92E0253470EACA68E52D96E747C172473A95E49D33A4FE6C23C490580
+F92AE6BDA56D0F1B6AFFAFF1F6BB81BB4B09587A562C3BCFA2F6F4D3A5974DA4
+8C686F32193C2849CD9E179D7C632B9B456B1A87CBE4A6DB0AA09607E9FFEFAF
+8D8A4B9397ABAA9EE484D097D9826F5207B5D8ADEEC4F0F38782C06340470479
+A7A569A8AD45A806AF0F772CDD520263CE87E39EFF08BA7450711FAE22046FD9
+EB1ED2053C120EC0915A2C19A32AF1432FCED97C336EDAC578869E74F0A0A124
+2D37720702FCEB5C9DED771A5272604EF0CD3BF23191E5F494122440BCD4C996
+432DA0B3951B7930F2EAADD5D7DEB960932ECC2428C28FA44288F2B53E16ABCB
+FE274DB85F462DD0A4F4A0C2960A6197ACF687C5AAF43E49DAD91996E2E194C9
+D7E6F2A050C41F87F98AA906B9AE85E95FDF7523D24965AA42BD255EEE0AFEA7
+91677C5363865A87138D5B9493EAD2802C78431D69225023E4C3147D7964B59C
+4769D96EB3813ADA3E77F4EF7CF90146A3E6CF7420F90EDF5661CD384086CAE8
+F5FE0A7619493F3BCC50998E0DCC31966EF0F799A5CFFA8EBB6065C4DBE04C5F
+ADE2D8499E00127D66331CE7F876BB343C333EE043A2565E1C834EBED857AE21
+6A9811EA5F44A402DFFBEA1613C43F766A6823DFA260F01CEF9A2F90C903AFAC
+3C76084F93716F1D2FEEAE9319168E049C9480B0E91631F41CB630C6AB4CE308
+3F24247F024114A8D1D758DF0F3543657C9FEC08BBEF2A8E62DF26A72230DF5A
+A0FF9C1EBD45F8F3A06DF0FF8B712313BF804F4DD2E7F9266BB53106A7C9446D
+8E301E3485E423BF6327544F41A8CCDF71CEC9F3D41DA616D23B489AA4E7A987
+CE859DC75C8C52F91D91A58DBB09ABAD54580C13E403273454C6785675EB8211
+15AC407D7C1B80F7E29EF25BF53571D39F6B474D7146560702C87EF9AB0FE893
+9551C7038E09A77AD011E940907C622BB9E5F21B42DF2051912104BEAFD0E739
+2D8B2C0E0B2308CD7DBBC551D77F50AE17E744FF4CCA83ECC6E7473DBA2AC0D0
+2925FE52660A776D8B714F5258E8D42CBB01185753B46F61A29095FCCA403846
+572D0B929980C2B39A573D00BA26CA79672BCB1ECAFC64E2A24774F63117653F
+28BDC06AF30555410CD372B30027C2D1E0F6DBED51BAEC760E11BC846996B4FF
+01E741E6AEA7B404DDE81485896280EA2D7A97D47887EF7356A11CFFB7D1EFA5
+4DAEB1A11D6734F10499A98331263F93B1FA059D3992563C5460B34960AC0FB7
+D17680B7D52B2D29E0264081DB8A099361A331958833EAD0CA131989125B1759
+FA11CF20319C4FC8EFBD0BA1A157AC84FE92F9D68D19CB2752B7241025E26C19
+2207A525F4B883FAF3B59AF4C61065FAA43B334491F668CFA3F94F2D9956FF29
+5BFD3DE321A6449432F7279D563D937FDCDD27463C60D6152CE655E01CCC30F6
+4ED119E8633A164BE26D90151DD17F8A3D55EF562762D6B685B7D9F6D4EE0233
+63DCE5418E180D69BA1F40C431E49DA720769A528920E2480FF747F9251CC964
+5FEC318DA8738DA93A187BC7FC35F4CCCACC31AE4B1DCDE8A0E52AE65C389C30
+548683D6CE11F6CF3A8881935DD81F9893D7E511EE7EAB5369AD6FFB2E54A3D3
+25E0B992FA47E99CA2E85EDA0C81099818AD2B223BE7CA6C166835D027E2FBC8
+B4F531440A95FAB954DD729F85C4C5A2ECF6D35CB33265F2B2EAEB5C49DD7CCA
+87F0B7241A0D4A4597EB4ACFFD3E9F1A30DEC256A6CC0001332886CB7AFE56D1
+FE2DDD6BB7DE61972C222BD34B923B4A3EFA3559D50F88F3542FC218B50B2AE3
+8B88A89F8198482BDED47894F09B78C368A05064913D072C63070CD9DA18780C
+3D88EF3C0068515474834D5AE97DB3FAAE42D682CEF1E51F73765805A2EFA642
+1B2BB41D2A3D66A25A8001323DECADEDFF2BD679B6BABF72D3102B1E80FE0B6F
+53934A43DA1DE91844C8E4FEC9E3872E72EB5323268E034A37447F387EF4254B
+8F8F868A9F9C2521499FD08A9D22ADDE6F5C7396F1E728857B23CFE9636EC910
+2CC746A0A615E7F135C53CA869739FDD8445290BA39387B9501BEB2A9C5F7B24
+AA732F91FC13E5DF75CA853C1D8A294AA417C62094CC1AA3605D0BB8C023CD49
+A4DFC1C5BD848D143922A2B9193384D51496FF5D0C3D9EE3CE30B48A90EB221A
+83A203BD05BC57ECBCA6D27FAE87F83842E78CA500E1752499622445194399FE
+28C671ACE2EFFCB86E61A8221F1593BB1D37801CF5AC4EBE8A85F26ABBE47E52
+9768463D454144213196E693F47E40C40A16AF5010912CA50B005FAB47F3E9CD
+C18198AE197D5AE8C68E3FB2762DEA5696261423E824CB99A5C6CE8870E8FDA7
+19F19FA1BA6C88ECDDB603E2624AAB64CA5D817E19F463E3C54984FBD31797D5
+96E261351EA9B8D0CA9F6156040180EAD73A630DC2DF9BC7288E83B5DD9895B8
+36BE5D0EC05F57BD0DB6B73F05415B1C0389C9857D387842D31DDEFAD60888BD
+1A877FBFA1618A813DA8B984B1124DFE780CADC7E1D849A58EB1482E15F38115
+3ADFDE10CB4C5B266E947AAB42E0A02A98443A8B4F277442A16159BB190DB252
+C8E27456C09A219EC0B9D057190B7B882E9408F25B0C48126E32764BC781B358
+83D9BEACE2F1AD015A477D109F850E3E5C083F12EFD87D3DD7ED2536546D8033
+0C64B26E61BB8A969AC4D28D1F6BB51C4217D4D8211B5BB33CA1B5AF6F842836
+EDB4417744FED0E89EE95001E7D191EA2743A43E317EF272CE15CDC234E5F6BE
+680A41E4B58D84676AF3FB9790CBF98A8FDC3CA10203C0F0E4EB1B64968BBAFE
+1D03DA2CB88AB3044D2EFEA94B0992D2E07C6849C9E86C39CD4D964B5B1045CD
+5D58A77B0E73D1796DC07A4FCD6607262A11B4F55CD672F49F65D6E9CBB55519
+7AD359DECB1FB493E84AE5ADFADFE069735E828B9D4F44BAA6E298BA6F98DB29
+B1D4F9F6956C8B2BE8846574B50A1B2D06EC392C60429B762F1336472E768497
+D70D9DC9D0D4C121F0723E1D725F8A669AE44B2891F2AC0CE16BB0E65BC7C549
+4D15D8CAB38682E60E6FBD74AF35473E7877F7E0739A1D2F1DF39A1CEEB9AEBB
+1BC5564802FE41A783C7997512EED5A00767D3FCC384B8C7DA97CAC37E547D1B
+ED70138287183F8AE4F5877E16066825A8DE41377C93CE53DADD5C7FBC3A288E
+23D7C1A5EEE3B0ABD70EDB1BD1CA86BBF083803DA04ED7603195733BB51D1952
+0269192362B338E9F6AB3DFD1384A9BA22E16E2E160C621D20C16DDA5BB93C63
+ABF409EE25B160835D7E55409A7A7B65B4F519248CACE4DE7E326FAC6E9D79E8
+9197B6384B806ECCABD44388C7A911BF60F03084131C2EEFB53F75C4868EC380
+5B8F7264061333F2F236DE20E59DB052CC7057AA867B49EE9343296241C6CB6C
+C1F3664F3D4680A4F337DA52FD775CFDD5250384D0E17CA46B3A32B6F6E91182
+B7D7C16230AEA9016133DEB70543C068F4CF66BC94EC6E35AB48E87690E7180D
+2D79B85E57F3AEE86A4C240B417B3A278A66615EE97C96CE6652CD87289A7B93
+0509DDB0BE2B9F10CCAD247ABB6BD9C4A1536CC2BB71316371A3CC92EF2891B0
+0D2B73EE9C177B82D7F3FD6C097DC9A80D12665F8B8DE6972D877995EAB5686E
+32E43D1B3E1166F8A54BC121FB6768C75010CD7A06B7CC246E01957160FB6D1E
+0F560DF3E13870D29E69473F1E160A83F58DADF487C91587DA03FE3DBECC4BD7
+47463A6AED62657358BDE5FA2FE64A830CFD7D2E1A1A62BC6ED64D7E3411CF8B
+3F64DF1FF713CA0D4335FB6BBFB3FD81DA8DCF889A17786378758E473A8E1915
+8B2E746F9F4B6C437CF316BAB7A803416FF656D498593995A161EAAD1A5C3F66
+33D8306FD30F1A99E555D7E5BA9F105190971A5CC51940BB3EC5BD7E9BA0BFB8
+9509200B67475C4B62C78D2F7258323192634CD895EBB4FBB6ADB0604E1ABC9E
+CD365097B29E4C7695BE1FEA9BE8BDBCD40A7796E64874997EFB8B89EA18CDC9
+AFE589BC15ED790281A05C9AE9D38B439E16B7897CE9AAEF3E00FECF70C7C963
+7558BEC2F70DC3180A651918B6BCEAB07E14D48D561257659CDA05DB9EE7F00D
+BABC069746EDCD19BE906C1A8A77BCA105EA54E562974AB08FA2433663F286EB
+E80C4EC07B34D0D122EDFECFC0D3E089B4593AD63FEA93C545FD63D195E6C68C
+979DC2D454A6D185418DCC5822040496206F87FE0C83642F97568F2F2EA2B945
+252446BC1412AC181025E6B1B0FDB6B1382C6BEB199F9A104DA7415E90990B26
+6B2AE09B0BE58A8D3134FA2E4D2DBE49A25A988379323E26C26691F98AAFA77B
+95422519DAB484F35ECC882808741496CD5C71EE374DC97F1B5B0369DE48DFF8
+9CC61303D6FBCE95FB2EBAD303046D3375B91129F13C30ECD0F352B29AA73B8E
+9BBA5F849AE43B2BFA5DCBD05E645734A3E1F5DEAC5BE34B19E3B68B886A72C7
+460A773DF3604F5FB744EA9905AC65D756B9FC47745670E7858C83266BEE1C5F
+A2CC250CA59D8B04DE66BCF41487631D7E978C27E0BB998B8EB54208F0B21FEF
+D172AACD3F8E6FABC60E51FC105D3F6EBF19A2E1E73295AC49CE66B9F2F1BF5D
+0A1D8CEBF89121A4587E39BB62167DC15F4D32648AF0A43D8929CA8FBC78621D
+C3DB61C2498974A02CC340CC4A574F0E60152A0D4102B55318B07857C57D13BD
+B6111D8D8E9852274B7E649AC22B893A21508372648557FA2CD28C95F472B7D5
+3673874130AF14C7B9326ADECEA73DEE7BAA3AD842DAD823A041438935FB3D47
+FC8B4DE75CB449A90D1F5D94703C3B12F3B8FD016D95D7068A8F6C93FA932880
+2DDBEBFD7F36FCE1927547617121D03B1C6A7F496615B1868253594D03DB6375
+F6B77864C29C663AC6FDCB34B0ABBF559BB29BCAE4A8B726F01B38CBCFCDF626
+DCFB584F055E41DD29917297001147E074A3822B0B41DFCF1ED12A0FC69B3A1E
+2B2985125FA3AB6051E61FAD0B66DAEA287BC9C91EBA95E01055C0FFF4B811B8
+629B8D9D4E0D85653D64F9AE567EAA910EB8E9CE8CE260974ECC02E279AF8156
+6B8096F83FC9CB9B902EDF5B926FB8C8E86EB9C3A36CB8DFDF10F9605331963E
+2F4AD2F1F64554C1EE470E5E96BEF1E0CDFD4107B302B33BB7935B54C9CBA6B1
+EEA2A586FB09768C66DD48009E3C3D4C28AE2E4B9FAF12387889EF05061BC7B3
+CACDDE65F50DE176B15DCD15418173126CFD3F68093537DD43BB658216BCF65E
+A32358F888B0271A06DB84AA5BC03B10F67B7FF921689837D62591530D7E2F5C
+E4E34E0D3ACC218BD2793EB6C5C7FD31F0B2D40FB0C60EDB0C9883A4883892B3
+EFA7A3685991CA4E9765F6C0EB6231D89CE48C917E632C79681369BE19C7BFC9
+9B70F6333CB91C160545F827BFF527D201CCBA409DF6F61CF6860B378C64C57C
+19644BB9F05604A198EAB9371F5E16A17E610AE4908A76A739CD587C2FBFB87C
+7872C2DD74D5D313D22B33EE2F64A5062193B969720560FED6D2E6F284179D43
+6157B02BCB075FBD34D68335D8C6E190DED3AA46B9F57664F5F4EB7D3734DD79
+7CE8B85E8D2DF7205C6D92BC2946320D21FFC0E89F7832B21B3FFC04B495E015
+9A741644AA80DA77673CA09453DCB54DFD8A7CCB0C179F8A87F8809FE19EC6E1
+489AF10ABCDC8F1FC85AD101D40F186234306EF0BD631B896D4BE6F475A22820
+B9F4358C1E58936C8085B216FEF406CBE8C010E9024D4AF9282F18A927838F96
+C72C75935E67FE707A728821855622B393F54C2E5C6512795ACC687F028276A0
+E6022C7C48A73DE8E1364E6EC7E9109B9FD3596002E9DABCB9985E9298DEFB1E
+A6E649AD2745FB77257C1F6A61846C35CC7DEF4207EBCDDD6F76398CA95AB7D1
+A5A88EC11A0709467CB39F287AF7A10108630CAA9615DC227AE76ACA2E53233D
+AE2C4177A18FE832AB80EDDCFE61045790DAE39365E6CCCDC8E38378FE947C86
+6B6DA30DEAC6DD565550174023A2859820771B1854A2E9FCEE82BCD94F2B914E
+C4011E7B4AFBF1FC211340C8E5A66E4DC1ACF66C83C2E3841434F4EB2D76F0ED
+C1A62DD5891F809A5B8C6D7269E8165122FB4E8EDBDA9DE3BCA562DEA2098A96
+5D2DB6E41DAADE6F69C0F02AF0E05E74AB2163371E10E4E199256ECDDAF9FF5A
+8AAC829B9105B79BA863DADCE4ACAAE5351A31543794C4BA54C862DC73A4BB42
+213CC668576C3D6D8D42D99340B491402F0B712FA4580922694DF0A8A463D3FC
+051CF050C124BD1F730D762BA23EE523D95AAED4FAB9392153E8C6B5D75818C9
+2093D642AC8627DCB3E287F45D62D1AAA4BB6153CCC54F2504437CCAF1AE406F
+919E2B51F6F76AC51987935574DB4A6109CABB006EBEC482662A344C2E72DF86
+049AAB12F3016FAD368106BB0A969B85BF152405EB5589E4BD6385B1BA3010C7
+D7FE6A651A1DC4B732C61E084B4BBCB50B5F4165FCDD3B7D384D61C592E65770
+3EC9A658429C3E96C940C2A2A7CF4BFDC5E61CDFA533BE7BF3B5154B3DAE5441
+9B3133B96D0CB64D8E55E89590A50E12B57C27FD5EC65D7632E9861FD029DC0B
+B05CB0E6222371D7D2D0D6661BB041F234A114BD422526385F52FDAFC016792E
+283EEAAAE1F6AFDCB46A9051085BA0FE0EAC7F6B812F5A6D65E9DA6713AF8788
+F4D14C3EE931021F8332D282A933E95C4882A3E12C4A2BBB7BCADBDDFC1F2662
+6A610B79E0B7740342A2317271E931E4D1C7B5B8AB4E9FC40AF2E67B93D540E8
+45DCF039564AB39151F4EACE7BB432929B5735CB12D731DD3995A2EB3E919CC9
+D79E0E329D5B8483229E013330DC6A324C83C685144D411803CA09D4A36887DA
+3D030AC820EDAA1AA767F49215730076C47C5263EB5061B4B9B5A49B7F2F325B
+1FE2A972A31909451F9611DEF3D1131476204E0FD5E25E90D34BCB9518301FA3
+FD005EEBDEA8A1D0F808C85FF5088D6253CB8AB3B5C5D8EC41C97406A79ABC33
+21436BD15791BD249489F00546E3DF4083820504B941C6191BBEF6AC989F2C43
+CAAFB1124873C0B35278C4463251867DE9E646E13195827A92D83E762D3FE521
+8FF5D7EDB2E2B246AD90B2B09A0E073D1709AB0D1CEDC286AF63400E645F7FB8
+40F98C20954FBBA5ED1A0ACBADDD0F5907B5696D54ED5280B1EFFF068DB13534
+B071D44C77DCA8C17D0BB95AE85B2510B79452062CD296ED62F7034C95736F0D
+3CB5A9B287787BF8C5738F5868CA3570DE56BA0502D55DEC9E9A3046377F2D59
+FC237ADAD36C22EEEC7B0222F45D6DE06486D165A9548E07FC8875957DCACD7F
+648C447D3442DF9A9F23768E796FC85221BBD079BBA01A939D82F2489F083734
+A8FECE716AD90C4800BB8853D1C726A81031EC6DC519DB16C631445511DBF211
+CB3A67E9B51E8D2CD8305B4E914C0DF2B6526122984747F23CAE19750D5D2894
+1D6788A75DBFC42F0EC87030924BB94E8A3597DCA4372A2DDFC181EDB7C145AF
+E4D24DB8DD7C36B0580C1EE70A741DDBFB49802E4C07CF1BC6A2C21801B1F8FE
+8C6CB6EC5F5ED20B93BC0CE0D9AF0AF29806B6E4551F0D5F585BAAD42E1205B6
+69E6B1959D4A86DD6895DED94327ABD889C3FA7FEEB7C240237BFEA12F24B5C4
+C9CBC9A3515FEEC3960F9EAC4122FDA903BDB15E2D70BE4E67329B293F10A07A
+031BE8633FE9DD33A5535E20CFAC263F614A00B24A9242BCF9DAE873116758A1
+6B42014BD0EB77652A4347478C4D5B28FF5AB11D794E00E4E95AA410E148F7E1
+F72BA05EA82F288E0D0DDB272F19B2EACD00C7CD37E057244C8FE2D6A992941F
+CA5C6C6B513635BCE0F313A1A81D62CBBEC88047D9E212FD671B033110EFBE7D
+28E2D03A41816F34BA815C39E3299B633DF2E6190D48F4EB8B9BB89FF99910E0
+8FC04444078109B1F5FDDFA32258341E1AE5D75260BA66A34CD4FB28F04DFAF9
+5DD3EEEC0837510CA2BF79D0024CDDA6217015152622534B85F0766E5A864976
+87EB1F38BB1395AA59D9F646D719894161F910D56E091585C76D273E3702BF39
+E7384252EF2BBAF3884898E6368FE9B625C2ABE7568367813BEF7B3B28149A94
+29FF02A4B0AD0B1FBEB0248634363B0EAF5D6F4BAF883BD554C374A3B02E756C
+6B087B042F2EF748DF70A2C48E22AB22FA00224E0B365C10ACC1F228556D3D88
+3DAFFE829A494CC8CF586D75458A4CAB86D157243AA3F3BAAFBF3FF594603299
+CB7D5ABF8D40F87B09BF449E93F1CA7C0AE4438980D2C98F738EC831FB992A5C
+C2A2699F8CD5F1B302F1AAB3C3151F06D50502CBBDC36E9D7CE45BC18DC591CA
+54BEABDB09BE80119755D0AC6D91356FAD5F76060ED0C66D353C96E2C3DB7086
+B16A6BECEF6A2502E997D4FE16B390F5D1C96C54C6EDAF3D80368FE691162F0F
+0BEE1CCBF682C480C3FC98CDCE768D5C237DF828389B31F15FAA56C017DCC9FA
+2619E2160CC66399F1AD974357B7B5E5972F8DFCB3034CFA59040F08FE1E419A
+193137024AD752B54EC86108596477C9C1BEACF049CB9D69C244F26C4FE5826E
+8D1094868DE869C35A2B58806A8533C8EF5D2DF21890F1A3BE3EA6C70D6D769A
+9F5549A9E965772B9D40F2A51A8CB350C82CAA20F7861C153EA82D52199A7C08
+39E8C6327D058593E0CAD9B32E9E69B8550C467EF83EDD211B00410C192B3119
+BFD6274B74DC63197584026A3940DFF551094608C824B0E66B4A95A58890AF4E
+934B3D39BABFCDA26D874F03E143E0BFDFE605512B46ADF223B3C9AA2A3957AF
+E4A47605B76B38F3076DBF918295678E85FD29C67E3FA09862DC663E58A594BC
+8B6E30C53A4BE967F11B97B26B5D554BC9954C0895A71EF8B4616832A428099D
+41F4340CA96DD09B612B4DE6B20EB05D7F7CC114E939D0A01049EA6B364E8A6B
+53111F3C842748CEE526342CC681CCDEE7ABD7F30C26D5FFDD279306142EDB19
+06C9A0ED4E8ED6FCFCD43776C4A6AA6F0604E5A5020743721EE05E71C6881DE4
+2BEA1C904693FA973D15FDF0636283D637F6C4D23E8D1C095501E6BC593AAE7A
+A53EDBDDCF4062A1AA8BC844278EE7CF540B3F4AFCC6659B5715DBBFF1C7173D
+F592920E68A0EDA7F176288572978DE52691ECAE3BD85FB91AFD10556CA2016A
+89BEB737C074E702A77765F4352EA49F9C7B1B8E5F981F5DB31ADD485213C190
+881036128F226EDE4D2D064374A6F66057C19A0580C2D928533053B2E3C42858
+46775EC712046DAE4650A6A64CE241341219FD92642570C85B4919CE4D2791A2
+67B29AE13C26699D4777C02C74CAF87D6CF0ED3D08AB508447192811B0E7F3EC
+F5032BBC3EFD618824D974AD5665904AFBB92FC18BF534691CE94346142FB2D4
+F28A3DC5B7569D48F2AF29466F6000574939EB8F3DDC6A3A618CA47446E95CBE
+0E6D95302D70C96FF92B7608BB3E18AC48AB71232D871772D17E3E8D0A3D1D99
+08DF0AEC4316CE34B72358BCF67F08DC71FBFDD4413C2C787679C5D4E983392C
+F21632FE23E5A6C2C6B6E11D3B225E852CAD35C85EFD2E4FED06B68EA1F8BA00
+488833B4CBE54763DF428D292032983115990F56CBD856D8CF4962B29E128268
+1720D2F2CCEC2EA69723BFED46ABC56F041E058B60027B5C3A66C355E8238805
+FBA5DD981FB3808F7F800E69A6B85B011B9F9B391E8AE835DE4BD5AF0880AF94
+ECF195F5B2BFC0A4B1911A421560FA20F6300DCC9E0885716CC42EDFB59F7F2F
+37CA82280D820D549B416CC00FB89E963D5861C8748CA729D4D37463E871A1CB
+5AFF926DFB7D2028F74A1561FDD799611EADD2417859B5D6963BABCA1D1B0AF3
+D3EFA530A87C144D18C7156DC85EFFDA40B2A77D41BDD3DA3950E0C5B677E3BF
+D0A50CF0E9DBEB3182F0CC7C7812B91CC5F057964E15B7639B6D99F7E65040EB
+9CFB300081ACE78FE5EC8E37837BA85009B2690D0B14C0AC1D1E6C1919900B6E
+84A2806FE2D603206FC48C743B1E8D7540EFCA33BDDADD5940D1E3D5B809314F
+7642C4124CF94D47B5EFC6174CDC00553C23123C24B53FE0979E7C83704A6381
+B0DB9AA8AA605DBC5B00EFB651B94FFBB3856544A9F0E05720728B5A79A447BF
+CF9825B926CF8503A0A46B837319080D7AF5C022A3E7D1F2C3C29E0D902E9AC0
+3F6931705301B1574510EA3A509981603B519EE5DFB8241D0D6C63F7FA8EC16B
+DE2FB14871FD6787FBEF560591456E8B26116A4CFD5214ABE046B18001DFF34F
+15A7E5A5BB7B6073BAFD8D65D31E59AA94985115F267A04FF7C2AFEBD64412CA
+8CD7B1B7899C53E7BC32F72B3A944D4A356495F9561153083C4C20F9BD23201E
+7BAFE0A6E059BE96D5EDFE1DD4CBA0B40F7E209E91DC7AAE8ADFE9E84C127281
+6437682C1457C7176E9B51F011FBF1B17911E7AA71A97BD55D920FDCCA9ABBA0
+D412F31EE501BFA7A2FE0BE47A98DCD0A36E7CCD8AFCC1608E0C27BB54B65416
+2FD4659120CCF13A28AA5DDE86C584AFD57EC9B257E55C40A4978F9FF17B9780
+A8C156D598F4DE7283C223A58EF896657E84577E60F1F702CC13E4464ED4C60A
+88B8A97AC870F8555578FFF82BD7063B2CAE4440C1DC4243ACE088FFB428E51C
+49641AAA53F1281DD70FA1E0DD48F790F181DFC912C8E9D749BE8E8F8B03612D
+24AD5D8E4AD5701149711CA838B238D487FA136A81D02378C0599ADEEFD8004A
+0ED71E38761224CFE7B69CDC20887AF19D5FE8177CE7091696BCB549A11E10A6
+B62FE410F38A1A71BF67EDBF86CFA498876E1D142524AF5A70D5973B3D83804E
+EBA95FD7529DFCE967FF96D2383ADAD1F8A5698E6455BF455BB23C0A5C07F6E1
+97DE6D8E2FC9462A82138BBE55045BD8257D6D1AF0D814D0D947505F4CA1C10D
+8ACF8824E299A7EB6363DCF86F76AFD3F41FBDA69A31568F88A7F6DD34FB6FA1
+2EA495E4DF6E34E1E954C223BD7FE152DEA01E7201DB986B83EC02E75B5D1A83
+2C267E10C43A2B989F1E667038743A4DC4533AD5EBB61954A8588F1AD914BFAA
+F8D9C091E36B87B6CA569FDE501FFCBE27BCB1432DC80584FE0F91AFD0C0073D
+E3EDEF55352D28BA680DBA8D33AF1BC8DA2124F7BFAA04D5179097AFFD9FF7B8
+634FE29D0DF784FBFB203EDFA739B305D5AD1DDD6A22330AA8A4F2663718F4DB
+F085555883A9F3BFBCD85BED2E5B88FCF16D122DFA6F52DC4F3A308EBFBF8EFF
+DF709C45B3306F9EB696E7DC0FC58B81D5E194FCB518E4AD4DFA8381D7CBBFC4
+3DDCBCC0BA3E5D448B12AFE9871CF7FB59612C487139E0B103881D46CA4F6E6B
+E0E462DACB8A69EBDE728E64D862A877DA51FD28D53F5C52D110D92C5B6E3D45
+636BBA91C29D7BF02B860128720FFF314776A1B96CC723D81122BAE381588AA7
+BB8F735C6A36692225ADE3AC1AA16EE8856B186BA7AA1A556CACE500B7245623
+25A374A4F01BCE3BF9A165CF37781606342E283BFF0C061D64771ADA815C76A3
+E946EBCE12695206BB0EA396AB34BD2DCF91C20D897D7A99754602ECEC561FE0
+7146CE351F1B9A9BE8CCF721CEE7579777FFF825ED8C808FD403F2E48DC8A9C7
+E98151E3D14E4D4FE68A39A56843B809CD654BEC9571FD596209EF0EA4D37CF4
+9BF85DC713CEF655311D57D6021F6D2FDC39B0E9A6CB3D3C07335CBD05A7A627
+4920FAA1C97E8A7B77590DE191D192CCA2C531DCD616A4DF0D5E345AFAE474D0
+A002546774F400F97E024BD19888026F8A7D78C5B64DBB572ECDC18B7427B824
+7247B7558D1B8F2DD30BE801D3295E6891B299CBF49F881A5E4F4EEE2FACE0C0
+3A73837D4FE5A0C48AD40EAE396C7C40041DCEBB76199BBD7FBA6142389988F3
+14CC7B3E7CFF331CE17718DF98D5868C7F20AE8E2853052E839700A3C8BBBD60
+8CEF9837F931475BCD6D7AF2835E89426356CE9BA42BAC4610A6666974FC333C
+0C28837E35B539D95F213698039C831677B011E74BADEEF03226A345FA69755E
+C79DEB00F894D86A3A6F6F25FF2FC808AB5EDC3DB4A0335B3374AFB993F131C5
+FB2C27097A4AC85648AB44DC2951DF5BE1E302B848EF900D15388DFE816C6CD2
+AFC28CC0953DEDA40FF5BA1BA22FEF0ABBB6B9C5886F5BCF37D39F871DFED145
+B751288DC682026E117A01EE06CC3A4448F6971E51585B89D2375FF336BEE56C
+32D5F31433ED3C32740A69DB94B50ABB3E8ADB24CC074CF6A00484CD811D78DF
+45BA57A7CDCE0B8FF5BAF56411CC9B654D5728CA3D6A90AF167975B4D6074371
+851FA80294C87B0B7A95C8BC7196084D86BDE2BF4015BBDDFAB4DE2C31BBB2C8
+C4DE9094993531657CA80286D4879A8D46BDFE0D151C2A2A11B6A68002C5FF2C
+D8C23BF5015BBD62BFB861037C64A5E354CF40BC04DF03D9C61640EBFFE1226B
+3E9BE0191532918B0679B55E3C958A9BBABE8A214A2E584B6674254C1C5842A4
+C7052454227737C9CC71FF2F201169038BDF4DFA4F65DF78C9AAD96939955F56
+A2C06DB97C2C6265B2BD4F8872257CCCFC7F5E1FB86D811DE77C684A89A1EB75
+F3F2536EF3688E57781000979D965DB1876C3BD55B9386BD9FCC5EEA596DAA33
+BFDC3BC5CF96EEAB5F4635F33A8083F45E79344E73B53D8A405D6AE48A9588C9
+04FF42ECD98CFA387F985F2C8698BC31E4A878C95BC5E62A262D2F5CBAFCAB3C
+9F3BA8EBE08BF93D73E95775D08C570B9AB080D4D9BC312A745B7EB455C1D6E0
+90A7072AAF3D7B7FD5114B7581DD0F46B32F020924995C71908B1E4EC322BED5
+0DEA3E62D5F00FBB0E354E836E3AE75AA46537FD2177DDA5E5C6DA4CAE9B390B
+D174DC84F24AC05703F640EE578567AC1583FF85CCE936E0499D822838E6D0BB
+F82DB5453A0C91FB323FFE8B7289ACE64885D2C7C5C0DF075C52FC1E738B5D57
+1A34A52C52C3E4FF0F16F6EAA0861048B3BC2FC588C05449F5A42602A77EC4F0
+4CF19DFEF5510099E7470D1254B0BD864FA634B7FDA7918BA63F2B88B43F92A3
+77F37D3BF6FEB38DA67776DE4743720F1920EC6723074C49AC14F4DAB91BC9DC
+F2D7337637D73157A8C7BD0FF88D0880C2F410B5A5F53D4F241C45C5576F9785
+A9D810A9B8F241DB4697E22362F4526294EE15FB193FD29F52A63EC4094E656A
+06A6E84347E4D47BCAA15BFF7D3DB02175CFAFE291CE225A613002EE6D8162AC
+6CAD256A8637172A4469B9CB3D570957E87E0817957BD75B2051858D7579D09C
+54EF49C2027BD532477B730CE703EC14C54FA2497712140E53BF25A4AC45A344
+DF16D5D824542E3EEC6D3326607C0EF862205F82844DE7E6B982D8C84981E142
+DC5C0FB44AB80BFDA0D3FC28474437E45C3B41457B19C6F1173ECECA4826D19D
+7A191D76BD376641C2EF99E1A9C848BD8CA250C9912BE5FC5877B88818D876E3
+6C095EF01D860C40B0FC7169FBB5AD992121EE6EF9BADA5B067E452D8FEA72CA
+20D4673D2E6310233BB66D52BA5E893A3177B20B1AA94AF16230482DA18CC020
+61A48695FB2DD30D83762595FDEDD1F21290871B1A2E82FD1E75396A2BE737E3
+6DD792306C62AA7E3A1B3541795F3322BA72A00061DD925A03244121CBF9D572
+BF4658620DAB84F46680086DD757D07EB4CFFA4D5A7F3D5DEE1D3156A9AEB636
+320AC7B07504607C15436B91C47EB7773755B51FAA977CB4F794A6CCCE04F0DF
+94DA510BD515FA0557BB2109B6A838BB28B761463429E801738CB4B76D5DF6CF
+2F36EA51D1247AA166E825D08CDA5F268E98639A79C721CA23D266294248E865
+ACFC113882E78FE7C7385F0E2C913A7E8838AD9C3A2E4C5C728237C2481388A5
+0A0869D6DFEA19FE7759C0D5D64266443529A1EC6C8F2661F72269D7343552A0
+01181BC161D5426BED82212DD9CECF208480E74ABEEBF9556A66DB3902E6A372
+A0AB02CBFF66B8FD896D8884084B271115C3D2F86D4BAB0783BE0D3B9BAF948C
+82054A87C5A1DD328E9215D3B8CDE33E978099595F6F2740679C200211580C31
+771C0F803B8B733D9716AF3B27970D473062F22C9742BAB029754903E0DED238
+CBE1F3B66E79584E19114B651A6F45C4E525157E425D34FFB976C7768EF8C0FD
+205F9B01AAC142ABD1AA336529005FB1091B6E00385BCBBAFB5E3C81BF3CDAD1
+6FF605F4069A34DC90A388FDFF1456826A7DF07B1F471DF49931C9635E8F214B
+967695E1E14FF05F743F43E359BCFCCA1153F7F253C1BE5AA6DBE0652B46ED43
+C0F3178A201D5C7E05E8B8BFAAC30E134B163E233176BA3FA06FEE966BC81F55
+80B2DF00322AFAAFFB56A986C3D6E50C87A73BA1148E8321693B65F64DE9C39C
+07729C7360AF458FA59717A71E142856DA36A9C6A0E78D8BF66B0CC66B4A702D
+70A0EAE80D3C75228C2E066445963073D4828019069420EB5C721A1CE57769C4
+48A3BD0DF632B4A4DB2E0012E0F7F546A54E4517FDA34E7B4469636B9CAAAFD5
+1753CCEDF14532414D6716F0DD4B297F294DCDF134511E8FE759114D739BDF9F
+FF77562EDC820D911924BFA9E7B537319EAE887CEADEBF0896F036BFAD4AED46
+657431DF132C3CA4596AE94C66ADEA665C779150356C0311F9DAA29D237D68B8
+D89D6AEA3363AEDAB0F7D8E49688AA561AAB9A751D0011BADE0388DD291D7299
+3CEEFFA3CB0241667BF429766C1C89C914DF3A7D4B97330BDB48E4256351B625
+DEAD87082F9A0E717F03251B4D53F33975DD7088AAF0ED1DB80E3B3851225D2D
+29A1F8B70579A39E097BC2254C55875232A33AC19FB8F86049C3FE21474FD90A
+B4F84D5E1D20F3B6A89B3EF996AE0108DFA485CB21F656F8D8930B5EA6F4C37B
+C25CADB2FD4C905E979CD8C498E42D68DB0285B121B4B38C7F3843492E27FE91
+72530B1BEE8CBFBE64F2FD1C83A46C7C8A106DCB5F3C9D205645DBDE03144508
+1F8F079761966F98A71E85A52D0BFBAE15CED8B6FE420BD485ACFB8350D561A7
+40DAC589FED2C8D53ACB63E8F5A0F00624409153E1ED583BFCAA3591BC7FC228
+966BAA1751CBB4AE1BDC8E025EA16DA2DBEED6F5E89FB8718781C0C70E5019C5
+36114763FAC3DD323F5354072E82D16B6F6C70335084D42C13A04E7BBF57F32B
+93A1EA17E434EF1E73F71449C9A2E3A4531C353F76DEF46085ED58B41FC60D52
+E8680297FB957792C40192A36F9D6B9EB12F30C7DC07EB51356CD557374C61DE
+3D2FCEC478CF4560DB80C80B5BAF1734BEF0E27B7A38557262444910B46560DE
+055EC7C6239E0FE8A1FD7658F4AC643C6FCFA2D3385F2C693374FCBDB8FD25AA
+91EFDDCFF35612832891CD2F565D1DD25040BA1F0A7DD668BAE0817A0CED19F7
+D6589866C55A79B2C31252001FF084D67141F87DCFAE18DCD8676E4F8018656A
+756805E4481A46D4EBB73A39DB6B4B9A8DAC28E83C8EFC69C4543A91726C4894
+CEDA62456A10F7C28C2839606EE19E711ADFE93C87107012F88419DA67677A1A
+94D25B1BE2BAF610869F56CC76BFE6857066A2338EEEEF0C4B3132E6F2261A7F
+0FE2F74BB2514EEAE92A1A211A2085D50C2CD914914ADDB5CB265C47E0EB99FC
+4480EAB881DFF9A41771DCC43CDE19E798B5DBCADDB39A91F6D4CD893C90D1D4
+5EF749FC2618918311286B8096E1A33019FCAD5EBBE9AF6AE8460529A5EB9725
+11EC7D9ADA84FA3B73CC02DEC5F18CF56929E3EBE7D634AA05260066B7DD1305
+E7B446C6706F3E71ABAD3403163EA42347E82DC3008DE044B861830BC306EE5E
+C9EAC9EBF6CC25336A5AA4B3FC86705C1110EAA31F4621996F56D084EB44DCE0
+012CD0D04861020DF932A40936212FB9B62344FF2E5205320795A2CEB3A93A7C
+953C2460B10F9FAE53813F641ADB94911A98B4CA88C44D07BF3A449C5FD061D1
+6E6F6278978E06AA7FEF976F6DE9090AAB7C85508AF36717503FBF12EED980E0
+95D309B901A928B40E564ED0385251493B93C8A1B1A2E0C2864E7FA56C70997D
+82173EE1F1D1E2DE91D122712601B075E81F60C8D807DAF40A6A2DB86FBF67C0
+C6A67E5AB96978EB78F45E588EC5CA78FAF8D3938DAF7574BD0C8A1E72CD4F53
+BD815C55D81BC99B9AFF67763EDE8233600361E8E47628D313DC5C8434659F18
+452BC080040371C3B49C6D3D8CDAC2E073D4A6C84E4510842B37E825188DE876
+B73F723A54FDDC3444C21E84486B65B184E446206AC6C8C488B0951D9B67E22B
+5FCF7D99E5E3BC571913AC5A2D2403F6BBA9CF20D9971F088669F500EF79E271
+598D63A40B87FF1DD53E432B2B8ABF0C42E5A51D418A6D38C1234A174DDEDA0A
+C2E412BDCE094ED780562DE0649914F8A4F5CE902EB34AF0B7373DB2D18A832D
+4484210678266D233EB9E67831E828A207E05F7589AFB820ADAF62D9ABB375DE
+114CE744527FCE2FA35D1D872F30208B331B4327B972341D027745C4B4CB20DC
+A7EC2686D157BAAF7524C901CD082BA51FC8F17E0B35743E189412F12B05E3FB
+16F26ED75CF6C2BD355974749B4C3625C070D0E16A2494AD1EBBD2A37AA3BAD2
+87B57CC1DB4F0A8854776559B3827220CE8F7CE17A0191507C40B2A72C0A5564
+1DBD6577DF18D4BB71BBEE0357389341A8FC781509BA47B505C9CF359C0DDDF1
+F809E0825F1C0675C44F998F857CD91B1B27C2E8FFE99D6437C502ECB4F66E7C
+7758154B03C3E44658F70AB0DB50DBD2759222D060CC79E1A0CA8D0481EBC65C
+FE1914118D893016D71F37B0C3E753B16993A00C8F7F994E46A73C7BA5262386
+B6D39491B2F18DB30F7DFF061AEBB847DCD6E6326BA7615E3DDDC8BE861C348D
+7ABE34E045BFA565905C868E95133041B57FA080F7508FE421EAC29F2F13B5B0
+7223B1F963788E1AAF42D5E441B06FF1B7A2467B86E05C4C90D94A824E23C529
+B06B3075CD6FDEA67E6D4D65696B577A4A05A4663BF4A11585819B85B6810EA2
+E005D5669A9988F9B287C981364555F5211DCE3A175DBD8E7A322E31B69C966A
+BE89551B84FB04652290AA1CC07260EA4E5814CE910D2C7DD48357813D9EB9D4
+C220157B43C1091E128EFDFDA97F0402F999E02EDEAB0E643201D8AC884B7E4E
+6A92433A0EBA2524635770EC9140F7112354CC63F4476F7DA470050D7811A921
+02DBFDC954E9ACC0994394F7306B0BAF5C015BEB89EADBBE52BC4992B8773C3F
+B0725E8EDAC8CF90935AF853B1C2B4CA867AEE5D067C60C1F6D18027222943DC
+87B308A212FB59551A0AC3066D66A1752382783A9CC9A6F775FFB0F6A55E9399
+22CC038DDFA2AD6A039311631B4BF037124E0259ADA79B854CDA381078ECA286
+72E9816250187A5B4760117549FB06628728F671F499E5749FA2B21E105ED5CA
+EFF970B731B58715F9228E9E9CBD1E0565E633234857051AD219A5BC14380C9F
+5F8F61EF0D98D68AC4A62320FE8B7876E3DCC43147578B875A4E8B59A8EF6304
+6DECF0505CF4A4F589A3C28448B3F67998FF4F2E9CE81077B77D0D71982CFC7E
+E4DC174F9C3EDEB3C8491C61B150982F32293EC9CF9DE7105AEB479FD69F36D7
+54F3B381DAFB7A65BD6100F155A30A513BB79FEB24A03292811A04517937AAEE
+D183ABF019493C2874E140399D11FAF10B772671419838AD0A12CAF0BE290415
+169D746C20BDCAF5737036AC853F9D81E3E90DD553395AA400140A0EB0836D81
+192941B3577E8A72638AA275B92F9D48A45C265E5C059BA852026483FF7D8205
+06A19DB05F3BE1BD0466D20BAC9A054010538D76BB5F92061DA0F051011CB541
+5CF6E15FCED73C545F238346DF521AA3EB09131C03002EE06B72421E9E63E00C
+EEFDD453EDEC1DEBC8870641E88A3BF8B1DFF18DC0F55D896BBF710CF1FD01B7
+DD06F726DD6046E83E6E108599E8B23405390106EA8D86C78E48F80C00908FC0
+E8AFB264586F836B39924AE1CA69E386A00B6892425EA270900AFC5B0ACA1116
+B3DF99A3AD62A1007EFE59BA4E9C2B9AA1B65F355916508BBC8C071A3316975B
+ED7BBC94A92DB5E1A64A9374B1F713FE9C95694CF30ACE7DDE8DBEED3EB0D3F1
+A41C7FE9FDB9EC5DFA674A7CAF99F16C79042441F4886CD41CF9F55C936D670E
+032D70395CD358119925A395976EAFA0ED0A22B1578DF7BD3366FF6EFE369964
+8ADFBFB8B0D3C5C9BF586BE6DB0954EDF3D839085D5C0AA31EBD97F5A5E09FD2
+20910D7D4A54728905ED6CAD86C92F71503822A8C874E93F82EF9BA0E35C94F9
+CF342D28D65A89258E3258414DB504229E81E7298DAAE6848C2495EFFF169FB0
+6EAD806218418C918EF588932AE1E44E6AD0DF2D9684455E3EDBE66363C2B3B0
+5D1A78916120D57C45EDE32F49D9520E01A24610BCF47C2360A6D70CE9ABCDE5
+97F38A7464D2E75602E99B7BD5D01B882CC8D706BF1250FD2B1DEFE66B7ED82C
+EC38581CB9165B6B52FBD615F786DAB51BD78D846B2B19DFA59C562B071A2932
+94AEFA3F158571C5BC8E1C436109E3D2BFF6D266A8FB589FD343583F9E3B2C64
+026ACA216B2FBDCA13C6CFD91A0CD2D3712D79ADF4AC85AFCD6C6B09839C8165
+151B93F5F9A2799A0BAC2A14794D1FD7F6891925FEFD6643A5F25DDE4E09344B
+64F0A51B07095AC2379C84328BDCF83599DD68FD8A0825DFE26BC9CC84C9C5C5
+21A85554971A9C200F6386542F9C8DFA7C6F89F572CDFB96821DD0FA18821B0F
+3D113C3D1B6E19381C1634B4F578D261B5DC34B1F64EE30A701746AB4F90AD37
+E96607528C15EFCB75BA7C67093A962299B7B194C8918DF3E41D1ECA02A0AD4E
+CCCCC8201D0F9433C8824893F73945FE0CFE366DEDADB3F4268A827AAFFF3B11
+6773FD03D79678EA7F23E047B2D04B529E317AFE568E22C8125DD6CADF28B718
+4EE8E6C06C01E1B0F45D778D819922785EBC883657B4FA4F1D98CB6D04C95101
+D219A319FC407C9EFBC9A6676289820903E876F620819BFD6CBE1FAB37AB04CC
+50AB16636D1FA22A5C2937D924EA82A344CBA0C1EDE1141734713AB2F42F48A5
+51E078217142A320ADFEDCCAC3D3CF7C1789660ED052E87A65D91B586C0073EB
+3581F4F52D08B5A4E2FB8D8FF91F607683D6E1C9197213F8E83E250BD9D6AFF4
+54E44444C42128A7898C2847FFC33CBCAD468FBBD2EF4BB8332395643C9E4DFF
+5424F837D7C2CAE52890A9F22064FB926E15C1D4DDEF9A4A32E02F55357F21E1
+48ACA7E663AFED067C76BFEE9AEF65E8160EAE749A42EFF6CD71074AFF8394B4
+EAE419A2344DEB603CD292DB6961395642116AD61E984E4756F4670A03741FBE
+9A959BF0052834558CF6A73CB6E21BAFD9FFA803EF2473C6FE789FBB1F0C81BE
+78850AE8EF6D53C94579E27BECA5C520F21B12B45137016DD802531F5C9A3599
+861A916BB47DBFA14A32150C4C681CAA5BADACB937953D2799984DFDA1386538
+300DC63D6C99549A90A5E9A8106D80D23DBAF785ED21E0745B5DF6A94F67E9B6
+48A26A297B334F38059CB9AF0B6E6A898E9B29615CE41E32C06D1D867705CB28
+207726EB3818FE9E1C833DB148783E64F8B0577D423718E345A689D8748656DE
+CA58F072B948C0B54BD6A889F4A1225D460A0552B9175BB6733DF157F87D664B
+1C9B914A28A6120A1FF23C2B6DCB270190D90DBD838D0759A59995BB96F260C5
+B7C49DC66FCF17620ABD269053F742707EB2F27FAC805F0684B0A6C0B5853E3D
+E5647817168DC16096E8962E3C14ADDF49DE7449225C729B4830F4D0651A45D8
+F5ABA98F7FECBE3FB02F49D3BCEDC8E366769DE821FDBA3840F55F47E4101C37
+67B327475461583F56B9D4DAD9AAB899FFB4DA3D4F6AF0FEC0A0241860BAB912
+543D9E51370EFA9F882FB277E446937F861AE2DA4F138BE19BE5BAF338E349EE
+A3F8E5BA85EC9EE02AEDD271BE768B35F65191F7658EE41DB5B79EA49A206992
+41E6F081EAA7D086BDD111077B9BD20A418528F1A2BA20218185C624A12A71F3
+120C4DC70AA0FD1CBCBF9BBBBB5465C99F176BF72021C26A0C6E780467EA8808
+753206AAD430C6CAE5130C0FFAEEF6C43056CF13EC9267F4884FCE8B189A0DA9
+DBDA730C3D1BAB2D794BBCFD07A8F7894E20DD3086AAA31E299CAFEE29C5DDF3
+1B0D041E6B1905F54EBD72DEBB284186E7EC9866B733005A062CFB8ED79B7B75
+9B01674DCA7C5E2E479BE170C4C0BB57DA2F171A4996FBDC2D622A99CFDCDA5B
+F8EF6C270D52714145BA799D7B35987D2971ED9A3E490D5CEFEBD56BCDE9F441
+029CE3E560F02E2D39ACE9FC3F767B85410A6460A36538A9B926959B0CC879FD
+88D293D99B657C87A7F971064ACC371A7F2CB25FEE8A33EF7701108FF0DFA2AB
+AD56906F6225098D8063E05E3B75AE082106926044FA59C169CFC05502C69DFB
+F2B259C1740B2DC23F3568DDE0487FA5D7F1C53BCD605ED98E07F6CD774FFC8D
+3DE5E7535561E6EBE582766B5396A869F8A1AF2388AF309969BC5762599B04F0
+18CCCD57C6031F2543D266B247342B6F9B4CE9C8CF05314F5127EB6D0ED697E3
+7E7D6EFC6D3665700050A5F8865319EA2690EB056AFB14D13F069AFB0BE3C86F
+85367D422EC94CBC4D0C009746817DE55D2B6CF09754F22CBD9C7EA621C55C79
+DBB3AA440322CEA7A3841AB5FC7054B2E6683EA055437A35D42C2962A60EFAAB
+858EBB6D57D48FE75D97E6D7A0CDE3F4A19367A4B6E4BD1E678686CFC071F002
+51C3884CD5E95D2640181D2DD73A62EE2D7FD5CFDB30C5648CD090D3E889D65B
+D9BB799FE98CCC57D0B40FBC0813A6BFDE8CE8B38A56AEB3F34EAC849A6BA649
+7A14714C4351CC04883E6581C7926323441D716BC23D202AF22DE6C4FDB4D727
+971D6DEB55C6F57A9C42CCFAB724800E4CE936C40A254C2205FCA94C98521C40
+C12D11E1A4C0F2FDC14B2B341A5262C6C83B20C97400BAE5DE986A063442B3C3
+C7B9F127BE5810AA39BF50795B16F0C5CBD9DB827DD0B8F8F0EAC4B0C9349270
+6B045BC9079B8FA2044EA69063E035C69737BBEF0FD946545D7F664C3A4A1471
+19CF2BAC3EC3F5878C129ED81DAA9B92B295450A9DF2BE084071058EE434906D
+A1AF4CDE9D7E478DACCCB10B48CA31BA88D3851A7E5EA2CF2FB932EEABF237A2
+BD93C7A092BA7FA570AF2DE43EAB43599081AF5F3318D56D8F4C2B2EFC1AF6F8
+051C754779ED01EA030414B190A081645505DE0F4D0A3B66AC353F81CBB06370
+F33C788FD6EECD9ACDE798B479A2102C269BD62052478BA0C5BD7936E9E1EC95
+2062D2AA3DE8A04438CAAAC857805586DB0A4231F34A61B05441ABC93325166C
+EE085FEF2DB62147DE3CBB8D2F24687E4E7977F4C3136A458C5752598C83F616
+729D130787F6E2A6AE62FA4EE63B005AC66B57B4043A9DEE58004A8B70E576A5
+39B6675834258F0A803E798EF7DC0E5FE1BB5EE995FBF365F8B5CEFB56084E1F
+77548CA35FA2A28D007FF110D47CAED5E962E5A367B3882A75E867DE736050B0
+AC18034B8C561BE4E2F06EE92CED884CEB0D09A0C7707C2B1AD3163CC4F07BE6
+D0ACD9244E5C9EF238407D0743BD972892B53BA71489AD43F7E67312A1E21ACD
+9BEB69DD7617738168CE0C440CEC9A462737CA8FF67ACE5CAEDF0D642645F09D
+3BF2C8FDADD94B70298A9A89C6D3691F483CE233D726C9184E1B74ACB8C2598A
+183709AA4968F4E66014681DD5A70DB3599940455BFE78AFE566052482E0A17D
+D5BF829F24C47A1AD30F20ED91BAC83A7C001BCF8B22F7CCADD43D7075E865C4
+71D996C4641D9E96F0E5C4D38B07F29A96F19EFC4FF4147F1B31180866E52EDD
+654143D390587D23409B0D7CBFB0DB3D33200FF7F6815ADF70011FA2C6E9BB2A
+E0D01F904B0E036DBA77BA8B535E44D91DDA9CC7F10124C06AFC898CC8D26BAD
+A7D285A200C0175152A60ED12F0475BAFC54EA03F2854A48A312A61333F161F7
+23298F782A8AF7E5998AD7F22DDBCF54C7A9ECFECEADF1B78CFF915DF5F73D26
+8D700A26CE9FB11CBEEE1629E9F75AEA98E1392B27766B0E1A51A95811DDB2FE
+F23694BFCB3E979587BD26315BAAED9FF607AECBA762A41945D182BD0688CE81
+C29F4863EC028E24FA005F32071B505BA717CE0B55013EC2797F6F373282F265
+4BFC2A76411F1A7F01F9192B773B2FA06F9DEDD90C89873765AC901204A1118A
+FFBE854DA9D5A1E9588C7746B14DF8D413C4FF0B7C08CEBCA150C92244281E87
+FE02CCA9168E4C61866601B65EA3002B7195CC48D22D097C01DBB678746E9492
+CC304EF0AB198FF208291340585F5F44C2EC444E41DE5B5E3A7EAD4F69BE3324
+3DFF06CB1574798D339D47D84741B3F69550A41ED7C6FAC82344D7955E5B1BDC
+3416FE4118134F7723DA0B74B45338BBC60E94E88BBB0BC9033775DF75C39A76
+F19C9760DA504EC51890E78959DE4E0113F12E8A945FDD184973A92962E265C8
+3EDFD94DE761E6B576071E8CA62C32DA8748A849C9249EDA7C6382DA73FCF59E
+1BCE44E5F1E515E222C19314A58F7D4A1B9B40B3645F4CFB930E9DCDF00FDEE2
+92602A89B82A8314ECDA526DF40660A5B621BFAAE228514596194147AB8ADBA3
+E311A419B473040F02EACEEC7E082CF966E929E5F72A2CA143DA16390194F538
+D688F5AD85AE3F937E94C47359C650CDBF1269EF91341B2FD1846D3AD289AB49
+4F5AE12CFBD5FCE7E3CDBD3B03ADB70EE2FAD7FE76BBB323672FF66852023B37
+40388D56EDBCCF43EEAB3786DACE8FBDE47F9FD2ED0D15F4CD195D11CB1617D7
+8E2D6D1268358F69F5BF6E0CDF1E58AB4E502A8784200EA9761043543D55960B
+940EF24176D8F7678A62280DA8A26787132759FB02735C4D282996DAD1C9BAF5
+CD38D1A7CE454D4F5484FDBD9E7E903531AA0BCC507B9E03220E99B2C80F3DB3
+3F92AE097A972397EFFFCFF3321DB15C4D582770E8901603C25A8E47A724E96C
+06B1C3F12720A9D0659AE5D59C0D3F161127FCED30C17E6EC31EC5DAD844CCA7
+E4D83C9A3A867E5D6E70E2D149B8D54AD9348B5E38506E09314ABD82971078FF
+1C4FCCF17982DAACD827E63CDE25DEE4B3B21E516BAAB03AD4CC7E6E5C817398
+3FB83CCC12A3FEA6E0118F5AF6EEB8BD7EFFF500BF321FE73563590C21D83890
+509EE77E1E9BDD98DE7B5F61A67242004D545DD6E41ADA0DA16ED098518122C1
+7B2F99FB3E365134601E93173C548FBE7994FD7963344468E295C9252AEBBC7D
+3CD82A14EA2F5E0E9D45928CCFB4F5D74473FC49217628BA3F72EDCF42E4E303
+6467CF6251D05732D19170BDF9C763D9BE69D6F98CF945241390DBCE620E296E
+88000CFD20A6714DB1311B66AD5618BC5FD3D53FAC8515A383CBC7B353324499
+AFDC81CBF4C5937FD3BC77F9F4DC0BDBC6F1330D71F7279BDFEE228087961EB0
+C4B84086ECBA1DFC2BC9F76DA5EC1D3656A2DAB41E125553C5052A73E57F25A8
+1C114F2F40563A3FCDA80B99AEE9F509214ECBED0B55CB051563E5B90F3F8167
+64FA9A4E837BECB98C0804C82B011656E674036CEF570CCB31587F5A93AAC20B
+10B63B2E5AD83C153D8A25A4F0440610A1513AEC5E4A3317F4AD0EF3098F22FA
+32DEEDB0ECF8D997EDBF37FF554B4DCFB8D3159F04BD7B4492472466AC082CA0
+F15ED01BBD7B879208F71BAE66031082288A7F927D6A5DBABB3743CE064D03AC
+111FB99CB37E3F0279B9D2AE4EE389BBD63BC1C099F4A2A80CB405E627F785ED
+7B723382187CFE71C5138135A1CAD9319B8B2E73DE4D39DDB2E6673ECA7447B2
+B9F81C70D1A11C72DDBF2579DCC6CFD28DBE42AF2C21022A0E5109DD1ABEDC90
+73EC0900094863170F873A2F7FB719D485725D6125FCF00CE71F7B9D0AB0D5E9
+8F7587B2DD27F44A1970EED04C44CAC776DCD485E8D39DFA752627FE33937610
+B69BF261C38F26C7F55523BEC338BB0805C2F1DE28F2081FB1A23865F8603273
+37D4595A7AFB8F7B1FC5B68E63E0FC65C58E238E6E924A7A5A9F57EC89A397EF
+7C13FC02D965CE8C7BC577911A8B85C5D20CCF3CAB829C621697F0C9D6507E70
+06A14BBB40A3993F59C035833F8DD35A1453DF39659F72D169BEA31CE0AF3A08
+AEF10E19DA566EAF4E627305E072611795EAC4875B4919FDFAB74D7961D2F10E
+3350A868C38CD8D23658D46582DC397DC868A4299BA2CD2F953EC146658EB7C6
+A46B6B1F5DCE2EDA407BE98592407DA2C1618FB5AC32587F6D5AE7187FCD4919
+868F47583E51A9981B202C03BBD1AC359799EE08D39A0C0876754C0F9DDA31B8
+48C195D00E16F1C13EE3A3261F684E8B95EEECA768393B932C77A850D94F6980
+DC05F8000A9B6C368FE60BC3A880127598A22B7AB9FD791A66D2854341822493
+828DEBA62F669D1BCA3CF912E4CD616E5D8AB8729B05D147D545983ECBBB17FB
+ACBD731A17EE08CD89AB3FBFEC9E08C364168390A1E49FB4AA0C65836F578E2F
+1879E1FD1B100EE39AF490B2004CEE8E425BE6DB29E1D964A37FC8E8021B4967
+168FFE7DFCF8E8181F299922900855C7797A252C7A83C369DBD6D6A652A1F9D0
+D73FD5AB7F368CB83D0DC51A00EC74B54A406B5D83FC366C4BF7FC3E8AB8BB7E
+78569D4577267AB2CBD872BD190338A277FC0637FF571D8CAED2BCBC5BE6B537
+C2A72894AC2091B778493428D5EF1A238E77E7AB585BBCCDFC1F987CAA34F729
+ADB3BC05ACA3DD01B7C3B975149507F2EAA6DC2E76A933AE14FAF54DEDA6B605
+DAEAD123D80B6A952F6504F0B48EC88554156CAC701391793F230CF8B2C0FB91
+065CDD2D45733D
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+%%EndFont
+%%BeginProcSet: texps.pro
+TeXDict begin /rf{findfont dup length 1 add dict begin{1 index /FID ne 2
+index /UniqueID ne and{def}{pop pop}ifelse}forall[1 index 0 6 -1 roll
+exec 0 exch 5 -1 roll VResolution Resolution div mul neg 0 0]/Metrics
+exch def dict begin Encoding{exch dup type /integertype ne{pop pop 1 sub
+dup 0 le{pop}{[}ifelse}{FontMatrix 0 get div Metrics 0 get div def}
+ifelse}forall Metrics /Metrics currentdict end def[2 index currentdict
+end definefont 3 -1 roll makefont /setfont load]cvx def}def
+/ObliqueSlant{dup sin S cos div neg}B /SlantFont{4 index mul add}def
+/ExtendFont{3 -1 roll mul exch}def /ReEncodeFont{/Encoding exch def}def
+end
+%%EndProcSet
+%%BeginProcSet: special.pro
+TeXDict begin /SDict 200 dict N SDict begin /@SpecialDefaults{/hs 612 N
+/vs 792 N /ho 0 N /vo 0 N /hsc 1 N /vsc 1 N /ang 0 N /CLIP 0 N /rwiSeen
+false N /rhiSeen false N /letter{}N /note{}N /a4{}N /legal{}N}B
+/@scaleunit 100 N /@hscale{@scaleunit div /hsc X}B /@vscale{@scaleunit
+div /vsc X}B /@hsize{/hs X /CLIP 1 N}B /@vsize{/vs X /CLIP 1 N}B /@clip{
+/CLIP 2 N}B /@hoffset{/ho X}B /@voffset{/vo X}B /@angle{/ang X}B /@rwi{
+10 div /rwi X /rwiSeen true N}B /@rhi{10 div /rhi X /rhiSeen true N}B
+/@llx{/llx X}B /@lly{/lly X}B /@urx{/urx X}B /@ury{/ury X}B /magscale
+true def end /@MacSetUp{userdict /md known{userdict /md get type
+/dicttype eq{userdict begin md length 10 add md maxlength ge{/md md dup
+length 20 add dict copy def}if end md begin /letter{}N /note{}N /legal{}
+N /od{txpose 1 0 mtx defaultmatrix dtransform S atan/pa X newpath
+clippath mark{transform{itransform moveto}}{transform{itransform lineto}
+}{6 -2 roll transform 6 -2 roll transform 6 -2 roll transform{
+itransform 6 2 roll itransform 6 2 roll itransform 6 2 roll curveto}}{{
+closepath}}pathforall newpath counttomark array astore /gc xdf pop ct 39
+0 put 10 fz 0 fs 2 F/|______Courier fnt invertflag{PaintBlack}if}N
+/txpose{pxs pys scale ppr aload pop por{noflips{pop S neg S TR pop 1 -1
+scale}if xflip yflip and{pop S neg S TR 180 rotate 1 -1 scale ppr 3 get
+ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg TR}if xflip yflip
+not and{pop S neg S TR pop 180 rotate ppr 3 get ppr 1 get neg sub neg 0
+TR}if yflip xflip not and{ppr 1 get neg ppr 0 get neg TR}if}{noflips{TR
+pop pop 270 rotate 1 -1 scale}if xflip yflip and{TR pop pop 90 rotate 1
+-1 scale ppr 3 get ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg
+TR}if xflip yflip not and{TR pop pop 90 rotate ppr 3 get ppr 1 get neg
+sub neg 0 TR}if yflip xflip not and{TR pop pop 270 rotate ppr 2 get ppr
+0 get neg sub neg 0 S TR}if}ifelse scaleby96{ppr aload pop 4 -1 roll add
+2 div 3 1 roll add 2 div 2 copy TR .96 dup scale neg S neg S TR}if}N /cp
+{pop pop showpage pm restore}N end}if}if}N /normalscale{Resolution 72
+div VResolution 72 div neg scale magscale{DVImag dup scale}if 0 setgray}
+N /psfts{S 65781.76 div N}N /startTexFig{/psf$SavedState save N userdict
+maxlength dict begin /magscale true def normalscale currentpoint TR
+/psf$ury psfts /psf$urx psfts /psf$lly psfts /psf$llx psfts /psf$y psfts
+/psf$x psfts currentpoint /psf$cy X /psf$cx X /psf$sx psf$x psf$urx
+psf$llx sub div N /psf$sy psf$y psf$ury psf$lly sub div N psf$sx psf$sy
+scale psf$cx psf$sx div psf$llx sub psf$cy psf$sy div psf$ury sub TR
+/showpage{}N /erasepage{}N /copypage{}N /p 3 def @MacSetUp}N /doclip{
+psf$llx psf$lly psf$urx psf$ury currentpoint 6 2 roll newpath 4 copy 4 2
+roll moveto 6 -1 roll S lineto S lineto S lineto closepath clip newpath
+moveto}N /endTexFig{end psf$SavedState restore}N /@beginspecial{SDict
+begin /SpecialSave save N gsave normalscale currentpoint TR
+@SpecialDefaults count /ocount X /dcount countdictstack N}N /@setspecial
+{CLIP 1 eq{newpath 0 0 moveto hs 0 rlineto 0 vs rlineto hs neg 0 rlineto
+closepath clip}if ho vo TR hsc vsc scale ang rotate rwiSeen{rwi urx llx
+sub div rhiSeen{rhi ury lly sub div}{dup}ifelse scale llx neg lly neg TR
+}{rhiSeen{rhi ury lly sub div dup scale llx neg lly neg TR}if}ifelse
+CLIP 2 eq{newpath llx lly moveto urx lly lineto urx ury lineto llx ury
+lineto closepath clip}if /showpage{}N /erasepage{}N /copypage{}N newpath
+}N /@endspecial{count ocount sub{pop}repeat countdictstack dcount sub{
+end}repeat grestore SpecialSave restore end}N /@defspecial{SDict begin}
+N /@fedspecial{end}B /li{lineto}B /rl{rlineto}B /rc{rcurveto}B /np{
+/SaveX currentpoint /SaveY X N 1 setlinecap newpath}N /st{stroke SaveX
+SaveY moveto}N /fil{fill SaveX SaveY moveto}N /ellipse{/endangle X
+/startangle X /yrad X /xrad X /savematrix matrix currentmatrix N TR xrad
+yrad scale 0 0 1 startangle endangle arc savematrix setmatrix}N end
+%%EndProcSet
+TeXDict begin 39158280 55380996 1000 300 300 () @start
+/Fa 136
+[32 2
+ [23 18 23 1
+ [21 24 1
+ [28 20 2
+ [12 3
+ [21 24 23 1
+ [23 16
+ [28 1
+ [31 9
+ [31 28
+ [12 39 [{} 17 37.708344 /cmcsc9 rf
+
+/Fb 138 [84 1 [63 4 [84 8 [76 86 17 [110 10 [117 71 [{} 7 137.500000 /cmcsc10 rf
+
+/Fc 137 [21 21 21 1 [21 1 [19 22 21 26 18 6 [19 22 21 1 [21 16 [26 11 [29 28 15 [19 19 14 [32 35 [{} 19 33.583321 /cmcsc8 rf
+
+end
+%%EndProlog
+%%BeginSetup
+%%Feature: *Resolution 300dpi
+TeXDict begin
+%%PaperSize: a4
+%%BeginPaperSize: a4
+a4
+%%EndPaperSize
+
+%%EndSetup
+%%Page: 1 1
+1 0 bop -158 2763 a @beginspecial 0 @llx 0 @lly 890.299988
+@urx 909.700012 @ury 5102 @rwi @setspecial
+%%BeginDocument: ../texi/gnus-big-logo.eps
+% Copyright 1992 Corel Corporation.
+
+% All rights reserved.
+/wPSMDict 150 dict def
+wPSMDict begin
+/bd {bind def} bind def
+/ld {load def} bd
+/xd {exch def} bd
+/_ null def
+/$c 0 def
+/$m 0 def
+/$y 0 def
+/$k 0 def
+/$t 1 def
+/$n _ def
+/$o 0 def
+/$C 0 def
+/$M 0 def
+/$Y 0 def
+/$K 0 def
+/$T 1 def
+/$N _ def
+/$O 0 def
+/$h false def
+/$al 0 def
+/$tr 0 def
+/$le 0 def
+/$lx 0 def
+/$ly 0 def
+/$ctm matrix currentmatrix def
+/@cp /closepath ld
+/@gs /gsave ld
+/@gr /grestore ld
+/@MN {2 copy le{pop}{exch pop}ifelse}bd
+/setcmykcolor where {pop}{/setcmykcolor{4 1 roll
+3 {3 index add 1 @MN 1 exch sub 3 1 roll} repeat
+setrgbcolor
+pop}bd}ifelse
+/@tc{dup 1 ge{pop}{4 {dup
+6 -1 roll
+mul
+exch}repeat
+pop}ifelse}bd
+/@scc{$c $m $y $k $t @tc setcmykcolor true}bd
+/@SCC{$C $M $Y $K $T @tc setcmykcolor true}bd
+/@sm{/$ctm $ctm currentmatrix def}bd
+/x {/$t xd /$n xd
+/$k xd /$y xd /$m xd /$c xd}bd
+/X {/$T xd /$N xd
+/$K xd /$Y xd /$M xd /$C xd}bd
+/g {1 exch sub 0 0 0
+4 -1 roll
+_ 1 x}bd
+/G {1 exch sub 0 0 0
+4 -1 roll
+_ 1 X}bd
+/k {_ 1 x}bd
+/K {_ 1 X}bd
+/d /setdash ld
+/i {dup 0 ne {setflat} {pop} ifelse}bd
+/j /setlinejoin ld
+/J /setlinecap ld
+/M /setmiterlimit ld
+/w /setlinewidth ld
+/O {/$o xd}bd
+/R {/$O xd}bd
+/c /curveto ld
+/C /c ld
+/l /lineto ld
+/L /l ld
+/m /moveto ld
+/n /newpath ld
+/N /newpath ld
+/F {@scc{eofill}if n} bd
+/f {@cp F}bd
+/S {@SCC{stroke}if n} bd
+/s {@cp
+S}bd
+/B {@gs F @gr
+S}bd
+/b {@cp B }bd
+/u {}bd
+/U {}bd
+1 i
+2 J
+0 j
+4 M
+[]0 d
+
+0 g
+163.4 2.9 m
+197.1 51.5 223.7 94.3 251.6 130.7 C
+283.4 176.1 312.0 216.3 342.8 256.8 C
+373.2 303.2 401.1 342.1 420.0 396.9 C
+421.2 403.1 425.1 408.9 424.5 413.5 C
+395.6 371.6 368.4 326.2 337.2 285.0 C
+306.1 247.4 276.3 199.4 244.5 161.5 C
+212.1 116.7 182.9 79.1 168.6 20.4 C
+166.3 13.9 164.7 8.1 162.4 2.2 C
+162.4 2.2 163.4 2.9 163.4 2.9 C
+f
+0 g
+428.1 170.2 m
+428.1 170.2 429.7 170.2 430.0 170.5 C
+454.7 211.4 474.8 275.6 504.0 301.9 C
+512.1 300.6 515.0 280.8 527.3 283.1 C
+534.8 284.4 536.4 284.1 542.9 288.9 C
+571.4 331.1 600.3 374.5 623.6 423.2 C
+640.2 454.7 661.6 492.9 663.5 517.6 C
+660.3 515.6 L
+633.7 468.6 613.2 419.6 582.4 378.4 C
+572.1 367.1 566.5 352.8 550.7 348.3 C
+543.2 348.3 536.1 354.4 530.5 363.8 C
+528.9 367.1 528.9 368.1 525.4 369.7 C
+495.5 333.7 466.7 282.8 446.5 233.5 C
+436.2 206.2 433.2 190.0 427.4 170.5 C
+427.4 170.5 428.1 170.2 428.1 170.2 C
+f
+0 g
+754.7 271.7 m
+783.8 345.7 780.3 386.2 794.2 447.5 C
+806.2 497.1 819.2 543.8 843.5 614.9 C
+869.5 690.4 875.0 731.0 888.0 787.1 C
+892.5 826.7 892.8 865.9 869.5 898.7 C
+853.9 908.7 841.9 912.3 822.1 909.4 C
+785.5 890.2 764.1 846.4 749.8 799.7 C
+750.4 793.6 750.8 791.3 755.0 788.1 C
+755.6 788.1 756.9 788.1 757.9 788.1 C
+772.8 803.3 773.8 842.9 796.8 849.0 C
+817.6 849.0 826.3 847.7 840.3 834.8 C
+855.8 799.7 856.2 789.4 858.1 755.0 C
+855.2 687.5 836.7 643.7 819.8 576.9 C
+801.7 513.7 781.9 454.3 772.8 406.7 C
+766.3 361.6 755.0 332.4 754.0 271.7 C
+754.0 271.7 754.7 271.7 754.7 271.7 C
+f
+0 g
+383.0 484.8 m
+421.2 539.0 420.6 593.1 405.4 650.9 C
+395.0 674.5 382.7 683.6 367.7 695.0 C
+354.8 681.0 339.2 664.2 330.1 640.2 C
+330.1 640.2 330.1 638.5 330.4 638.2 C
+351.5 628.8 372.3 592.2 378.1 567.2 C
+381.0 544.5 378.8 505.2 382.3 484.8 C
+382.3 484.8 383.0 484.8 383.0 484.8 C
+f
+0 g
+120.6 509.8 m
+171.2 511.7 215.0 550.7 255.8 589.6 C
+283.4 609.7 302.2 627.8 315.8 663.5 C
+280.8 636.9 238.3 595.7 192.6 571.7 C
+179.6 566.2 162.4 565.6 147.8 570.4 C
+139.4 578.2 136.2 580.5 136.5 588.6 C
+144.6 635.3 192.3 684.3 217.6 724.8 C
+223.4 738.1 235.7 745.9 238.3 758.9 C
+204.3 726.8 174.1 677.1 147.5 634.3 C
+127.1 600.3 95.3 560.1 102.1 520.5 C
+107.0 510.8 111.8 513.7 120.6 509.8 C
+f
+0 g
+621.7 657.7 m
+669.0 661.2 703.4 716.1 724.8 769.6 C
+730.7 779.0 728.7 785.5 731.3 792.9 C
+711.8 758.5 695.0 728.4 656.7 720.9 C
+638.2 720.3 635.0 721.9 624.9 732.6 C
+621.7 736.5 620.4 739.4 618.1 744.3 C
+588.6 683.0 L
+593.1 671.6 598.3 665.5 608.1 661.9 C
+612.0 661.6 617.8 659.0 621.7 657.7 C
+f
+0 g
+502.0 681.0 m
+526.7 680.4 547.7 694.7 565.2 716.1 C
+576.0 734.9 583.1 755.0 592.2 775.4 C
+592.2 779.6 591.5 783.2 592.8 786.8 C
+582.4 775.7 571.4 752.7 549.7 746.5 C
+520.8 736.2 500.7 751.4 481.6 766.7 C
+440.4 802.3 416.7 847.7 366.8 868.5 C
+346.3 878.2 335.0 875.6 319.1 869.5 C
+300.3 862.7 292.8 850.7 279.2 833.8 C
+285.0 838.3 271.7 828.6 277.2 833.5 C
+268.5 845.8 244.2 875.3 220.8 881.1 C
+168.6 888.3 147.5 809.8 96.3 789.4 C
+83.3 784.8 72.0 776.7 61.2 781.6 C
+41.5 794.2 38.2 804.6 27.5 824.1 C
+2.2 764.7 L
+9.0 751.1 16.8 730.3 32.1 725.1 C
+45.0 720.3 55.1 721.6 68.1 727.1 C
+91.1 745.2 116.4 758.9 132.0 779.3 C
+140.1 789.4 146.5 797.5 157.6 808.5 C
+166.3 816.6 176.1 823.1 187.7 827.0 C
+219.2 813.0 240.6 789.7 259.1 759.5 C
+275.3 782.5 284.7 815.0 321.4 810.1 C
+373.9 801.4 405.0 751.7 443.6 715.1 C
+462.8 694.7 478.3 687.2 502.0 681.0 C
+f
+end
+showpage
+%%EndDocument
+ @endspecial
+/OJ {
+ currentgray
+ 1 setgray
+ 3 index 3 index 3 index cvx exec
+ setgray
+ gsave
+ -1 1 scale
+ cvx exec
+ grestore
+ } def
+
+/OJ2 {
+ currentgray
+ 1 setgray
+ 2 index 2 index cvx exec
+ setgray
+ gsave
+ -1 1 scale
+ cvx exec
+ grestore
+ } def
+
+/OJ3 {
+ 2 -17 rmoveto 1 -1 scale
+ show
+ 1 -1 scale
+ 0 17 rmoveto
+} def
+
+/OJ4 {
+ 2 -25.5 rmoveto 1 -1 scale
+ show
+ 1 -1 scale
+ 0 25.5 rmoveto
+} def
+
+/OJ5 {
+ 2 -71 rmoveto 1 -1 scale
+ show
+ 1 -1 scale
+ 0 71 rmoveto
+} def
+
+/lars 1030 def
+
+lars 2223 a
+Fc
+ (Developme)p
+ (n) OJ3
+ (t)14 b
+ (P)p
+ (r) /o OJ2
+ (oletcul)n
+ (t)e
+ (Cad)n
+ (r) /r OJ2
+ (e)h
+ (#23)lars 2330 y
+Fb
+ (R) 0 /b OJ
+ (ed)51 b
+ (G)p
+ (n) OJ5
+ (us)lars 2367 y
+Fa
+ (People's)14 b
+ (Democ)p
+ (r) /r OJ2
+ (a)m
+ (tic)h
+ (N) OJ4
+ (ews)p
+ (r) /r OJ2
+ (eade)p
+ (r) /r OJ2
+eop
+%%Trailer
+end
+userdict /end-hook known{end-hook}if
+%%EOF
-\def\verbatim@font{\fontencoding{OT1}\fontfamily{pcr}\fontsize{10pt}{10}\selectfont}
\catcode `\÷ = \active
\def ÷{\penalty10000\hskip0.001pt-\penalty\hyphenpenalty\hskip0.001pt\relax}
\def \newpagestyle#1#2#3{\@namedef{ps@#1}{\def\@oddhead{#2}\def\@oddfoot{#3}%
- \let\@evenhead\@oddhead \let\@evenfoot\@oddfoot}}
+ \let\@evenhead\@oddhead \let\@evenfoot\@oddfoot}}
\def \newdoublepagestyle#1#2#3#4#5{\@namedef{ps@#1}{\def\@evenhead{#2}%
- \def\@oddhead{#3}%
- \def\@evenfoot{#4}%
- \def\@oddfoot{#5}}}
+ \def\@oddhead{#3}%
+ \def\@evenfoot{#4}%
+ \def\@oddfoot{#5}}}
\newlength{\headtextwidth}
\setlength{\headtextwidth}{\textwidth}
\ifodd\c@page
\dp\@tempboxa \z@
\box\@tempboxa \mbox{} \\
- \ifx \@oddhead\@empty\else
+ \ifx \@oddhead\@empty\else
% \rule{\headotextwidth}{0.5pt}
\fi
\else
- \hskip -2.2cm
+ \hskip -2.2cm
\dp\@tempboxa \z@
\box\@tempboxa \mbox{}
- \\\mbox{}
- \vskip 2pt
- \hskip -2.0cm
- \ifx \@oddhead\@empty\else
+ \\\mbox{}
+ \vskip 2pt
+ \hskip -2.0cm
+ \ifx \@oddhead\@empty\else
% \rule{\headetextwidth}{0.5pt}
\fi
\fi
\setcounter{tocdepth}{3}
\setcounter{secnumdepth}{3}
-\def\verbatim@font{\fontfamily{bcr}\fontsize{10pt}{10}\selectfont}
--- /dev/null
+#define cygnus_width 48
+#define cygnus_height 48
+static char cygnus_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x60, 0x34, 0xf7, 0x34, 0x36, 0x0e, 0x30, 0x30, 0xdb, 0x6c, 0x36, 0x03,
+ 0x30, 0x60, 0xd9, 0x6c, 0x36, 0x07, 0x30, 0x60, 0xd9, 0x6c, 0x36, 0x0e,
+ 0x60, 0xc4, 0xd8, 0x6c, 0x36, 0x0c, 0xc0, 0xc3, 0xf0, 0x6c, 0x2c, 0x07,
+ 0x00, 0x60, 0xc4, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xdf, 0x0e, 0x00,
+ 0x00, 0x00, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf0, 0x6e, 0x15, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
--- /dev/null
+#define gnu_width 48
+#define gnu_height 48
+static char gnu_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x02, 0x00, 0x00, 0x80, 0x03,
+ 0x00, 0x03, 0x00, 0x1c, 0x80, 0x07, 0x80, 0x01, 0x70, 0x77, 0x00, 0x0d,
+ 0xc0, 0x01, 0xcf, 0xc1, 0x00, 0x0d, 0xe0, 0xc0, 0x87, 0x81, 0x01, 0x09,
+ 0xe0, 0xc0, 0x03, 0x01, 0x83, 0x09, 0x70, 0xe0, 0x01, 0x00, 0xc2, 0x0c,
+ 0x58, 0xf0, 0x38, 0xe0, 0x6e, 0x0c, 0x4c, 0xf8, 0x8c, 0xff, 0x3f, 0x06,
+ 0x44, 0x7c, 0xcc, 0xf1, 0xf8, 0x07, 0x44, 0x3c, 0x76, 0x40, 0x01, 0x0f,
+ 0xc4, 0x20, 0x1b, 0x80, 0x06, 0x10, 0x84, 0x99, 0x0d, 0x55, 0xf5, 0x3f,
+ 0x0c, 0xcf, 0xf6, 0xaa, 0x8e, 0x0a, 0x18, 0x60, 0x3a, 0x55, 0x0d, 0x00,
+ 0x38, 0x38, 0x5b, 0xae, 0x1a, 0x00, 0xe0, 0x8d, 0xad, 0x59, 0x1d, 0x00,
+ 0xc0, 0x83, 0x2d, 0xad, 0x1a, 0x00, 0x80, 0xc1, 0xec, 0x5d, 0x1d, 0x00,
+ 0x40, 0x78, 0xc6, 0xa9, 0x1a, 0x00, 0xf0, 0x7f, 0x06, 0x52, 0x3d, 0x00,
+ 0x50, 0x5d, 0xc5, 0xab, 0x3a, 0x00, 0x00, 0x5c, 0x8d, 0x59, 0x35, 0x00,
+ 0x00, 0x96, 0x1a, 0xa0, 0x3a, 0x00, 0x00, 0xb7, 0x2a, 0x60, 0x75, 0x00,
+ 0x00, 0xe7, 0xc9, 0xc0, 0x7a, 0x00, 0x00, 0x6f, 0x19, 0x01, 0x75, 0x00,
+ 0x00, 0x4f, 0x55, 0xfb, 0xda, 0x00, 0x80, 0x4f, 0xb3, 0x8a, 0x8f, 0x00,
+ 0x80, 0x5f, 0xae, 0x0a, 0xee, 0x00, 0x00, 0xdf, 0x64, 0x4f, 0xe4, 0x00,
+ 0x00, 0x9f, 0xdd, 0x9d, 0x65, 0x00, 0x00, 0x7e, 0x9b, 0x3d, 0x71, 0x00,
+ 0x00, 0x7e, 0xb7, 0xff, 0x70, 0x00, 0x00, 0x7c, 0x6c, 0x3f, 0x7f, 0x00,
+ 0x00, 0xf4, 0xcb, 0x79, 0x30, 0x00, 0x00, 0xf0, 0x93, 0x79, 0x18, 0x00,
+ 0x00, 0xe0, 0xbf, 0xfd, 0x1f, 0x00, 0x00, 0xa0, 0x3f, 0x87, 0x0f, 0x00,
+ 0x00, 0x80, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
--- /dev/null
+#define gov_width 48
+#define gov_height 48
+static char gov_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xe0, 0x00, 0x00,
+ 0x00, 0xc0, 0xc1, 0x07, 0x07, 0x00, 0x00, 0x20, 0x30, 0x18, 0x08, 0x00,
+ 0x00, 0x18, 0xc8, 0x26, 0x30, 0x00, 0x00, 0x04, 0xe8, 0x2f, 0x40, 0x00,
+ 0x00, 0x02, 0x54, 0x55, 0x80, 0x00, 0x00, 0x11, 0xf4, 0x5f, 0x20, 0x01,
+ 0x80, 0x30, 0xb4, 0x5a, 0x30, 0x02, 0x80, 0x60, 0xf4, 0x5f, 0x18, 0x02,
+ 0x40, 0xe0, 0x54, 0x55, 0x1c, 0x04, 0x20, 0xc0, 0xe8, 0x2f, 0x0c, 0x08,
+ 0x20, 0x81, 0xc9, 0x26, 0x06, 0x0a, 0xa0, 0x0f, 0x37, 0x98, 0xc3, 0x0f,
+ 0x10, 0x3f, 0xce, 0xc7, 0xf1, 0x13, 0x10, 0xff, 0x1c, 0xe0, 0xfc, 0x13,
+ 0x10, 0xfe, 0x11, 0x20, 0xfe, 0x11, 0x08, 0xfc, 0x8b, 0x23, 0xff, 0x20,
+ 0x08, 0xfc, 0x4b, 0x65, 0xff, 0x20, 0x08, 0xf8, 0xb3, 0x34, 0x7f, 0x20,
+ 0x08, 0xf8, 0x83, 0x0c, 0x7f, 0x20, 0x08, 0xf8, 0x43, 0x04, 0x7f, 0x20,
+ 0x08, 0xf0, 0xc7, 0x87, 0x3f, 0x20, 0x08, 0xf0, 0x57, 0xd5, 0x3f, 0x20,
+ 0x88, 0xf0, 0xaf, 0xea, 0x3f, 0x20, 0x88, 0xe0, 0x57, 0xd5, 0x1f, 0x20,
+ 0x90, 0xc3, 0xaf, 0xea, 0x0f, 0x10, 0xd0, 0x81, 0xaf, 0xea, 0x07, 0x10,
+ 0x90, 0x0f, 0xa8, 0x2a, 0x00, 0x13, 0xa0, 0x17, 0xac, 0x6a, 0xc0, 0x0b,
+ 0x20, 0x3f, 0xac, 0x6a, 0xe0, 0x09, 0x20, 0x1e, 0xae, 0xea, 0xe0, 0x09,
+ 0x40, 0x3e, 0xaf, 0xea, 0x73, 0x04, 0x80, 0xf4, 0xb7, 0xda, 0x3f, 0x02,
+ 0x80, 0x10, 0xf0, 0x1f, 0x0c, 0x02, 0x00, 0x21, 0xd0, 0x17, 0x0e, 0x01,
+ 0x00, 0x22, 0xa8, 0x2a, 0x86, 0x00, 0x00, 0x04, 0xa8, 0x2a, 0x40, 0x00,
+ 0x00, 0x18, 0xf0, 0x1e, 0x30, 0x00, 0x00, 0x20, 0x00, 0x01, 0x08, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0e, 0xe0, 0x00, 0x00,
+ 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
--- /dev/null
+#define qmw_width 48
+#define qmw_height 48
+static char qmw_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc1, 0xff, 0xe0, 0x7f,
+ 0xff, 0xff, 0x81, 0x7f, 0xe0, 0x7f, 0x3f, 0xf8, 0x80, 0x7f, 0xc0, 0x7f,
+ 0x0f, 0xe0, 0x00, 0x3f, 0xc0, 0x7f, 0x07, 0x40, 0x00, 0x3f, 0x80, 0x7f,
+ 0x03, 0x00, 0x18, 0x1e, 0x86, 0x7f, 0xc1, 0x07, 0x18, 0x1e, 0x0e, 0x7f,
+ 0xf1, 0x1f, 0x3c, 0x0c, 0x0f, 0x7f, 0xf8, 0x3f, 0x3c, 0x0c, 0x1f, 0x7e,
+ 0xf8, 0x3f, 0x7e, 0x80, 0x1f, 0x7e, 0xfc, 0x7f, 0x7e, 0x80, 0x3f, 0x7c,
+ 0xfc, 0x7f, 0xff, 0xc0, 0x3f, 0x7c, 0xfe, 0x7f, 0xff, 0xc0, 0x7f, 0x78,
+ 0xfe, 0xff, 0xff, 0xe1, 0x7f, 0x78, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ 0xfe, 0x7f, 0xf8, 0x1f, 0xfc, 0x07, 0xfe, 0x7f, 0xf0, 0x1f, 0xfc, 0x07,
+ 0xfc, 0x79, 0xf0, 0x0f, 0xf8, 0x07, 0x7c, 0x70, 0xe0, 0x0f, 0xf8, 0x03,
+ 0xf8, 0x30, 0xe0, 0x07, 0xf0, 0x03, 0xf0, 0x00, 0xc2, 0x87, 0xf0, 0x43,
+ 0xe1, 0x01, 0xc3, 0xc3, 0xe1, 0x61, 0x83, 0x81, 0x87, 0xc3, 0xe1, 0x61,
+ 0x07, 0xc0, 0x87, 0xe1, 0xc3, 0x70, 0x0f, 0xc0, 0x0f, 0xe1, 0xc3, 0x70,
+ 0x3f, 0x80, 0x0f, 0xf0, 0x03, 0x78, 0xff, 0x87, 0x1f, 0xf0, 0x07, 0x78,
+ 0xff, 0x0f, 0x1f, 0xf8, 0x07, 0x7c, 0xff, 0x0f, 0x3f, 0xf8, 0x0f, 0x7c,
+ 0xff, 0x1f, 0x3e, 0xfc, 0x0f, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0xaa, 0x7b, 0xd7, 0x15, 0x73,
+ 0xb5, 0xaa, 0x48, 0x91, 0x9c, 0x14, 0xd5, 0xaa, 0x3b, 0x97, 0x88, 0x74,
+ 0x95, 0xaa, 0x28, 0x94, 0x88, 0x14, 0x97, 0xb2, 0x4b, 0x97, 0x08, 0x13,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc7, 0x98, 0x0f, 0x1f, 0x63,
+ 0xe3, 0xcf, 0x99, 0x9f, 0x3f, 0x67, 0x63, 0xcc, 0x9b, 0x99, 0x31, 0x6f,
+ 0x63, 0xcc, 0x9f, 0x99, 0x31, 0x7f, 0x63, 0xcc, 0x9e, 0x99, 0x31, 0x7b,
+ 0xef, 0xcf, 0x9c, 0x9f, 0x3f, 0x73, 0xcf, 0xc7, 0x98, 0x0f, 0x1f, 0x63,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
--- /dev/null
+#define ruu_width 48
+#define ruu_height 48
+static char ruu_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x83, 0x03, 0x00,
+ 0x00, 0x20, 0x80, 0x81, 0x04, 0x00, 0x00, 0xe0, 0xc3, 0x02, 0x03, 0x00,
+ 0x00, 0x1e, 0x02, 0x40, 0x7a, 0x00, 0x00, 0xd2, 0x11, 0x88, 0xcb, 0x00,
+ 0x00, 0x23, 0x30, 0x0d, 0xc8, 0x00, 0x40, 0x12, 0xa2, 0x21, 0x7a, 0x02,
+ 0xc0, 0x9e, 0xa4, 0x35, 0x01, 0x07, 0x00, 0x83, 0xac, 0x35, 0x81, 0x01,
+ 0xf0, 0x13, 0xb1, 0xa6, 0xcc, 0x00, 0x20, 0x60, 0x6a, 0x6e, 0x86, 0x00,
+ 0xc0, 0xc4, 0x4a, 0xe6, 0x23, 0x01, 0x00, 0x48, 0x4e, 0x60, 0x1a, 0x00,
+ 0x00, 0xb0, 0x08, 0x00, 0x0d, 0x20, 0x00, 0xc0, 0x01, 0x00, 0x73, 0x38,
+ 0x60, 0xfe, 0x01, 0x80, 0x1f, 0x0e, 0x3c, 0x18, 0xf8, 0x3f, 0x18, 0x00,
+ 0x28, 0x61, 0x08, 0x20, 0xec, 0x61, 0x70, 0xfc, 0x18, 0x20, 0x0e, 0x7c,
+ 0x40, 0x60, 0x38, 0x20, 0x3c, 0x0c, 0x40, 0x0e, 0x78, 0x20, 0xe0, 0x78,
+ 0x60, 0x38, 0xf8, 0x20, 0x0e, 0x00, 0x3c, 0xe0, 0xf8, 0x21, 0x1e, 0x34,
+ 0x54, 0x7e, 0xf8, 0x23, 0xc4, 0x75, 0x7c, 0x10, 0xf8, 0x37, 0x18, 0x5c,
+ 0x00, 0xf8, 0xe3, 0x8f, 0x7f, 0x2c, 0x80, 0x9c, 0x01, 0x01, 0x07, 0x00,
+ 0xe8, 0xe0, 0x08, 0x20, 0x0a, 0x27, 0x38, 0x90, 0x0c, 0xe4, 0x32, 0x3f,
+ 0x10, 0x49, 0x4f, 0x66, 0x07, 0x10, 0x90, 0x42, 0xe2, 0xae, 0x8c, 0x10,
+ 0x80, 0x24, 0xd2, 0x2e, 0x81, 0x03, 0xa0, 0x05, 0x49, 0x62, 0x01, 0x06,
+ 0xc0, 0x91, 0x28, 0x49, 0x32, 0x04, 0x80, 0x9c, 0x28, 0x49, 0x60, 0x02,
+ 0x00, 0x52, 0x24, 0x09, 0xc4, 0x01, 0x00, 0x99, 0x21, 0x09, 0x8d, 0x00,
+ 0x00, 0x88, 0x1d, 0x70, 0x59, 0x00, 0x00, 0xc8, 0xd0, 0xe8, 0x31, 0x00,
+ 0x00, 0x40, 0xd8, 0xe0, 0x00, 0x00, 0x00, 0x40, 0xc8, 0xb0, 0x00, 0x00,
+ 0x00, 0x00, 0x48, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
--- /dev/null
+#define uu_width 48
+#define uu_height 48
+static char uu_bits[] = {
+ 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x00, 0x00,
+ 0x00, 0xc0, 0x81, 0x81, 0x03, 0x00, 0x00, 0x30, 0x7e, 0x7e, 0x0c, 0x00,
+ 0x00, 0x88, 0x01, 0x80, 0x11, 0x00, 0x00, 0x66, 0x60, 0x06, 0x66, 0x00,
+ 0x00, 0x79, 0xb0, 0x0d, 0x9f, 0x00, 0x80, 0x14, 0x4e, 0x72, 0x21, 0x01,
+ 0x40, 0x66, 0x54, 0x2a, 0x46, 0x02, 0x20, 0x89, 0x24, 0xa4, 0xf1, 0x04,
+ 0xa0, 0x71, 0x93, 0xc9, 0x4c, 0x05, 0x50, 0xe5, 0x7c, 0x3e, 0x33, 0x0a,
+ 0x48, 0x2a, 0x8a, 0x4b, 0x94, 0x13, 0xa8, 0x98, 0x15, 0x89, 0x49, 0x16,
+ 0x24, 0x49, 0x2c, 0xe5, 0x52, 0x26, 0xd4, 0xab, 0xa5, 0xd5, 0xd4, 0x28,
+ 0x94, 0x64, 0xf3, 0x8f, 0x26, 0x28, 0x0a, 0x95, 0xfd, 0x7f, 0xaf, 0x50,
+ 0x2a, 0xaa, 0x7f, 0xfe, 0x56, 0x5f, 0x5a, 0xeb, 0x7a, 0x5e, 0x51, 0x55,
+ 0xba, 0x0a, 0xff, 0xff, 0x50, 0x53, 0xca, 0x0a, 0xf5, 0xaf, 0xd0, 0x50,
+ 0x0a, 0xfa, 0xff, 0xff, 0x5f, 0x50, 0x05, 0x47, 0xb7, 0x2e, 0xe3, 0xaf,
+ 0xf5, 0x47, 0xb3, 0x74, 0xe1, 0xa9, 0x0a, 0x8a, 0xd6, 0xd4, 0x51, 0x56,
+ 0x8a, 0xfa, 0xff, 0xff, 0x5f, 0x50, 0x8a, 0x4a, 0xe9, 0x97, 0xd2, 0x51,
+ 0xfa, 0x6a, 0x57, 0x6a, 0xd3, 0x5e, 0x0a, 0xda, 0x4a, 0xd6, 0xd5, 0x5a,
+ 0x0a, 0x55, 0xac, 0x35, 0x2a, 0x58, 0x94, 0xa4, 0xf3, 0xce, 0xe5, 0x28,
+ 0x54, 0x29, 0x9b, 0xc9, 0x14, 0x29, 0xe4, 0x4b, 0x32, 0x54, 0xb2, 0x27,
+ 0x28, 0x9c, 0x89, 0xbd, 0xc9, 0x14, 0x48, 0x32, 0x8a, 0x49, 0x94, 0x12,
+ 0xd0, 0xc4, 0x7c, 0x3e, 0x2b, 0x0a, 0xa0, 0x33, 0xd3, 0xcb, 0x4d, 0x05,
+ 0x20, 0x59, 0x1c, 0xf8, 0x8a, 0x04, 0x40, 0x2a, 0x23, 0xa4, 0x4c, 0x02,
+ 0x80, 0x94, 0x45, 0x42, 0x29, 0x01, 0x00, 0x99, 0x26, 0x04, 0x99, 0x00,
+ 0x00, 0xe6, 0x92, 0xc9, 0x66, 0x00, 0x00, 0x88, 0xe9, 0x97, 0x11, 0x00,
+ 0x00, 0x30, 0x7e, 0x7e, 0x0c, 0x00, 0x00, 0xc0, 0x81, 0x81, 0x03, 0x00,
+ 0x00, 0x00, 0x7e, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00};
--- /dev/null
+#define ubc_width 48
+#define ubc_height 48
+static char ubc_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0x03,
+ 0x80, 0xff, 0xff, 0xff, 0xff, 0x03, 0x80, 0xff, 0xff, 0xff, 0xff, 0x03,
+ 0x80, 0xff, 0xff, 0xff, 0xff, 0x03, 0x80, 0xc3, 0x10, 0xf8, 0x80, 0x03,
+ 0x80, 0xe7, 0x39, 0x73, 0x8c, 0x03, 0x80, 0xe7, 0x39, 0x67, 0xbe, 0x03,
+ 0x80, 0xe7, 0x39, 0x27, 0xff, 0x03, 0x80, 0xe7, 0x39, 0x33, 0xff, 0x03,
+ 0x80, 0xe7, 0x39, 0x38, 0xff, 0x03, 0x80, 0xe7, 0x39, 0x33, 0xff, 0x03,
+ 0x80, 0xe7, 0x39, 0x27, 0xff, 0x03, 0x80, 0xe7, 0x39, 0x67, 0xbe, 0x03,
+ 0x80, 0xcf, 0x3c, 0x73, 0x8c, 0x03, 0x80, 0x1f, 0x1e, 0xf8, 0xc0, 0x03,
+ 0x80, 0xff, 0xff, 0xff, 0xff, 0x03, 0x80, 0xff, 0xff, 0xff, 0xff, 0x03,
+ 0x80, 0xff, 0x7f, 0xfc, 0xff, 0x03, 0x80, 0x07, 0x8e, 0xe3, 0xc0, 0x03,
+ 0x80, 0xfb, 0xf1, 0x1f, 0xbf, 0x03, 0x80, 0xff, 0x7f, 0xfc, 0xff, 0x03,
+ 0x80, 0x07, 0x8e, 0xe3, 0xc0, 0x03, 0x80, 0xfb, 0xf1, 0x1f, 0xbf, 0x03,
+ 0x80, 0xff, 0x7f, 0xfc, 0xff, 0x03, 0x80, 0x07, 0x8e, 0xe3, 0xc0, 0x03,
+ 0x80, 0xfb, 0xf1, 0x1f, 0xbf, 0x03, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01,
+ 0x00, 0xff, 0xff, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0xfe, 0xff, 0x00,
+ 0x00, 0xfe, 0xef, 0xee, 0xff, 0x00, 0x00, 0xfc, 0xce, 0xe6, 0x7e, 0x00,
+ 0x00, 0xec, 0xcd, 0x66, 0x6f, 0x00, 0x00, 0xd8, 0xd9, 0x36, 0x37, 0x00,
+ 0x00, 0x98, 0x99, 0x32, 0x33, 0x00, 0x00, 0x30, 0x13, 0x90, 0x19, 0x00,
+ 0x00, 0x60, 0x02, 0x80, 0x0c, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x06, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x80, 0x01, 0x00,
+ 0x00, 0x00, 0x06, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x60, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0xe0, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
--- /dev/null
+#define upenn_width 48
+#define upenn_height 48
+static char upenn_bits[] = {
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00,
+ 0x00, 0xfd, 0xff, 0xff, 0xbf, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xbf, 0x00,
+ 0x00, 0xad, 0xfa, 0x5f, 0xb5, 0x00, 0x00, 0xf5, 0xff, 0xff, 0xaf, 0x00,
+ 0x00, 0x5d, 0x1a, 0x5a, 0xba, 0x00, 0x00, 0x95, 0xde, 0x76, 0xa9, 0x00,
+ 0x00, 0x5d, 0x2a, 0x55, 0xba, 0x00, 0x00, 0x95, 0xee, 0x79, 0xa9, 0x00,
+ 0x00, 0x5d, 0xfa, 0x5f, 0xba, 0x00, 0x00, 0xf5, 0xff, 0xff, 0xaf, 0x00,
+ 0x00, 0xad, 0xfa, 0x5f, 0xb5, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xbf, 0x00,
+ 0x00, 0xfd, 0xff, 0xff, 0xbf, 0x00, 0x00, 0x05, 0x80, 0x01, 0xa0, 0x00,
+ 0x00, 0x05, 0xc0, 0x03, 0xa0, 0x00, 0x00, 0x05, 0xe0, 0x07, 0xa0, 0x00,
+ 0x00, 0x05, 0xf0, 0x0f, 0xa0, 0x00, 0x00, 0x05, 0x78, 0x1e, 0xa0, 0x00,
+ 0x00, 0x05, 0x3c, 0x3c, 0xa0, 0x00, 0x00, 0x05, 0x1e, 0x78, 0xa0, 0x00,
+ 0x00, 0x09, 0x1f, 0xf8, 0x90, 0x00, 0x00, 0x8a, 0x3f, 0xfc, 0x51, 0x00,
+ 0x00, 0xca, 0x79, 0x9e, 0x53, 0x00, 0x00, 0xea, 0xf0, 0x0f, 0x57, 0x00,
+ 0x00, 0x72, 0xe0, 0x07, 0x4e, 0x00, 0x00, 0x74, 0xe0, 0x07, 0x2e, 0x00,
+ 0x00, 0xe4, 0x70, 0x0e, 0x27, 0x00, 0x00, 0xe8, 0x39, 0x9c, 0x17, 0x00,
+ 0x00, 0xc8, 0x1f, 0xf8, 0x13, 0x00, 0x00, 0xd0, 0x0f, 0xf0, 0x0b, 0x00,
+ 0x00, 0x90, 0x07, 0xe0, 0x09, 0x00, 0x00, 0xa0, 0x03, 0xc0, 0x05, 0x00,
+ 0x00, 0x20, 0x01, 0x80, 0x04, 0x00, 0x1b, 0x47, 0x02, 0x40, 0xe2, 0xd8,
+ 0xf5, 0x88, 0x04, 0x20, 0x11, 0xaf, 0x1d, 0x09, 0x19, 0x98, 0x90, 0xb8,
+ 0xc5, 0x05, 0x62, 0x46, 0xa0, 0xa3, 0xe7, 0x0b, 0x8c, 0x31, 0xd0, 0xe7,
+ 0x58, 0x39, 0x30, 0x0c, 0x9c, 0x1a, 0x70, 0xed, 0xc3, 0xc3, 0xb7, 0x0e,
+ 0x00, 0x11, 0x3c, 0x3c, 0x88, 0x00, 0x00, 0xf2, 0xc1, 0x83, 0x4f, 0x00,
+ 0x00, 0x4c, 0x15, 0xa8, 0x32, 0x00, 0x00, 0xf0, 0x72, 0x4d, 0x0f, 0x00,
+ 0x00, 0x80, 0x07, 0xe0, 0x01, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00};
--- /dev/null
+#define wesleyan_width 48
+#define wesleyan_height 48
+static char wesleyan_bits[] = {
+ 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00,
+ 0x00, 0xc0, 0xff, 0xff, 0x07, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x1f, 0x00,
+ 0x00, 0xf8, 0x0f, 0xe0, 0x3f, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0xff, 0x00,
+ 0x00, 0xff, 0x01, 0x10, 0xfc, 0x01, 0x80, 0x9f, 0x00, 0x30, 0xf0, 0x03,
+ 0xc0, 0x8f, 0x00, 0x48, 0xe0, 0x07, 0xc0, 0x47, 0x00, 0x84, 0xc0, 0x07,
+ 0xe0, 0x43, 0x00, 0x84, 0x80, 0x0f, 0xf0, 0x21, 0x00, 0x02, 0x01, 0x1f,
+ 0xf0, 0x20, 0x00, 0x02, 0x01, 0x1e, 0xf8, 0x20, 0x00, 0x42, 0x01, 0x3e,
+ 0x78, 0x10, 0x00, 0x81, 0x00, 0x3c, 0x7c, 0x10, 0x00, 0xa1, 0x00, 0x7c,
+ 0x3c, 0x10, 0x00, 0x21, 0x01, 0x78, 0x3c, 0x08, 0x80, 0x00, 0x02, 0x78,
+ 0x3c, 0x08, 0x80, 0x00, 0x04, 0x78, 0x1e, 0x08, 0x80, 0x00, 0x08, 0xf0,
+ 0x1e, 0x04, 0x40, 0x00, 0x08, 0xf0, 0x1e, 0x04, 0x40, 0xc0, 0x07, 0xf0,
+ 0x1e, 0x04, 0x40, 0x80, 0x00, 0xf0, 0x1e, 0x02, 0x20, 0xc0, 0x00, 0xf0,
+ 0x1e, 0x02, 0x10, 0x80, 0x00, 0xf0, 0x1e, 0x02, 0x10, 0x40, 0x00, 0xf0,
+ 0x1e, 0x01, 0x10, 0x20, 0x00, 0xf0, 0x9e, 0x02, 0x10, 0x40, 0x00, 0xf0,
+ 0xbc, 0x18, 0x10, 0x40, 0x00, 0x78, 0xbc, 0x40, 0x10, 0x40, 0x00, 0x78,
+ 0xbc, 0x01, 0x12, 0x3e, 0x00, 0x78, 0x7c, 0x0e, 0xf8, 0x03, 0x00, 0x7c,
+ 0x78, 0x70, 0x24, 0x06, 0x00, 0x3c, 0xf8, 0x80, 0xe2, 0x0e, 0x00, 0x3e,
+ 0xf0, 0x3e, 0x21, 0x16, 0x00, 0x1e, 0xf0, 0xc1, 0xf0, 0x23, 0x00, 0x1f,
+ 0xe0, 0x1b, 0x13, 0x49, 0x80, 0x0f, 0xc0, 0x67, 0x74, 0x51, 0xc0, 0x07,
+ 0xc0, 0x8f, 0x13, 0x55, 0xe0, 0x07, 0x80, 0x1f, 0x14, 0xa5, 0xf0, 0x03,
+ 0x00, 0x7f, 0xe4, 0x8a, 0xfc, 0x01, 0x00, 0xfe, 0x21, 0x92, 0xff, 0x00,
+ 0x00, 0xf8, 0xaf, 0xe3, 0x3f, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x1f, 0x00,
+ 0x00, 0xc0, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00,
+ 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
--- /dev/null
+#define yale_width 48
+#define yale_height 48
+static char yale_bits[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x57, 0x55, 0x55, 0x55, 0x55, 0xd5,
+ 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0x57, 0x55, 0x55, 0x55, 0x55, 0xd5,
+ 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0x17, 0x00, 0x55, 0x55, 0x01, 0xd4,
+ 0xab, 0x3f, 0xa8, 0xaa, 0xf8, 0xea, 0x07, 0xc1, 0x01, 0x00, 0x8e, 0xc0,
+ 0x33, 0x01, 0xfe, 0xfe, 0x81, 0xcc, 0x2b, 0x01, 0x00, 0x01, 0x80, 0xd4,
+ 0xab, 0x01, 0x00, 0x01, 0x80, 0xd5, 0x4b, 0x35, 0x6e, 0xbd, 0xa5, 0xd2,
+ 0x2b, 0x6d, 0x6e, 0xbd, 0xad, 0xd4, 0x93, 0x49, 0x4a, 0x21, 0x99, 0xc9,
+ 0xe3, 0x49, 0x4a, 0x21, 0x99, 0xc6, 0x07, 0x49, 0x4a, 0x21, 0xb5, 0xe0,
+ 0x0b, 0x75, 0x4b, 0x21, 0xa5, 0xd0, 0x07, 0x01, 0x00, 0x01, 0x80, 0xe0,
+ 0x33, 0x41, 0x00, 0x11, 0x80, 0xcc, 0x2b, 0x81, 0x33, 0xe1, 0x8c, 0xd4,
+ 0xab, 0x81, 0x27, 0xe1, 0x89, 0xd5, 0x4b, 0x81, 0x04, 0x21, 0x81, 0xd2,
+ 0x2b, 0x81, 0x04, 0x21, 0x81, 0xd4, 0x93, 0x81, 0x07, 0xe1, 0x81, 0xc9,
+ 0x63, 0x01, 0x00, 0x01, 0x80, 0xc6, 0x07, 0xff, 0x7f, 0xfd, 0xff, 0xe0,
+ 0x2e, 0xfe, 0xff, 0xff, 0x7f, 0x6a, 0x56, 0x00, 0x80, 0x01, 0x00, 0x75,
+ 0xac, 0xaa, 0x2a, 0xa8, 0xaa, 0x3a, 0x5c, 0x55, 0x55, 0x55, 0x55, 0x1d,
+ 0xb8, 0xaa, 0xaa, 0xaa, 0xaa, 0x0e, 0x70, 0x55, 0x55, 0x55, 0x55, 0x07,
+ 0xe0, 0xaa, 0xaa, 0xaa, 0xaa, 0x03, 0x80, 0x57, 0x55, 0x55, 0xd5, 0x01,
+ 0x00, 0xae, 0xaa, 0xaa, 0x7a, 0x00, 0x00, 0x78, 0x55, 0x55, 0x1d, 0x00,
+ 0x00, 0xe0, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x80, 0x57, 0xf5, 0x01, 0x00,
+ 0x00, 0x00, 0xbc, 0x3a, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0xcc, 0x30, 0x0c, 0x7e, 0x00,
+ 0x00, 0xcc, 0x30, 0x0c, 0x06, 0x00, 0x00, 0x78, 0x78, 0x0c, 0x06, 0x00,
+ 0x00, 0x30, 0x58, 0x0c, 0x3e, 0x00, 0x00, 0x30, 0xfc, 0x0c, 0x06, 0x00,
+ 0x00, 0x30, 0x8c, 0x0c, 0x06, 0x00, 0x00, 0x30, 0x8e, 0xfd, 0x7e, 0x00};
reading while bopping his head gently to some obscure music. He does
not have a cat.
-\marginpar[\vspace*{-2.5cm}\epsfig{figure=tmp/larsi.ps,height=2cm}]{\vspace*{-2.2cm}\epsfig{figure=tmp/larsi.ps,height=2.5cm}}
+\marginpar[\vspace*{-2.5cm}\epsfig{figure=ps/larsi,height=2cm}]{\vspace*{-2.2cm}\epsfig{figure=ps/larsi,height=2.5cm}}
-Graphics by Luis Fernandes. Set in Adobe Bembo, Adobe Futura and
-Bitstream Courier.
+Graphics by Luis Fernandes. \gnususefonts{}
\clearpage
\mbox{}
\thispagestyle{empty}
\begin{picture}(500,500)(0,0)
-\put(-35,325){\makebox(480,350)[tr]{\epsfig{figure=tmp/new-herd-section.ps}}}
+\put(-35,325){\makebox(480,350)[tr]{\epsfig{figure=ps/new-herd-section}}}
\end{picture}
\end{document}
+
+%%% Local Variables:
+%%% mode: latex
+%%% TeX-master: t
+%%% End:
--- /dev/null
+*.ps
+*.pdf
+Makefile
--- /dev/null
+infodir = @infodir@
+prefix = @prefix@
+srcdir = @srcdir@
+subdir = texi/ps
+top_srcdir = @top_srcdir@
+
+SCREEN_PS= group-topic.ps group.ps server.ps summary-adopt.ps \
+summary-article-c-ug.ps summary-article.ps summary-dummy.ps \
+summary-empty.ps summary-none.ps summary-unthreaded.ps summary.ps
+
+HERDS_PS= gnus-herd-bw.ps gnus-herd-new.ps new-herd-1.ps \
+ new-herd-2.ps new-herd-3.ps new-herd-4.ps new-herd-5.ps \
+new-herd-6.ps new-herd-7.ps new-herd-8.ps new-herd-9.ps \
+new-herd-section.ps new-herd.ps new-herd2.ps
+
+MISC_PS= ered.ps eseptember.ps fred.ps fseptember.ps larsi.ps red.ps \
+september.ps
+
+ETC_PS= bar.ps gnus-group-catchup-current-up.ps \
+gnus-group-catchup-current.ps gnus-group-describe-group-up.ps \
+gnus-group-exit-up.ps gnus-group-get-new-news-this-group-up.ps \
+gnus-group-get-new-news-up.ps gnus-group-kill-group-up.ps \
+gnus-group-subscribe-up.ps gnus-group-unsubscribe-up.ps \
+gnus-summary-caesar-message-up.ps gnus-summary-cancel-article-up.ps \
+gnus-summary-catchup-and-exit-up.ps gnus-summary-catchup-up.ps \
+gnus-summary-exit-up.ps gnus-summary-followup-up.ps \
+gnus-summary-followup-with-original-up.ps gnus-summary-mail-copy-up.ps \
+gnus-summary-mail-delete-up.ps gnus-summary-mail-forward-up.ps \
+gnus-summary-mail-get-up.ps gnus-summary-mail-originate-up.ps \
+gnus-summary-mail-reply-up.ps gnus-summary-mail-save-up.ps \
+gnus-summary-next-unread-up.ps gnus-summary-post-news-up.ps \
+gnus-summary-prev-unread-up.ps gnus-summary-reply-up.ps \
+gnus-summary-reply-with-original-up.ps \
+gnus-summary-save-article-file-up.ps gnus-summary-save-article-up.ps \
+gnus-uu-decode-uu-up.ps gnus-uu-post-news-up.ps gnus.ps
+
+PICONS_PS= picons-att.ps picons-berkeley.ps picons-caltech.ps \
+picons-canada.ps picons-cr.ps picons-cygnus.ps picons-gnu.ps \
+picons-gov.ps picons-laurie.ps picons-mit.ps picons-nasa.ps \
+picons-qmw.ps picons-rms.ps picons-ruu.ps picons-seuu.ps \
+picons-stanford.ps picons-sun.ps picons-ubc.ps picons-ufl.ps \
+picons-uio.ps picons-unit.ps picons-upenn.ps picons-wesleyan.ps \
+picons-yale.ps
+
+XFACE_PS= xface-abrahamsen.ps xface-aichner.ps xface-blanks.ps \
+xface-cosgriff.ps xface-drazen.ps xface-gertzfield.ps \
+xface-goldberg.ps xface-graf.ps xface-hardaker.ps xface-hedbor.ps \
+xface-ingrand.ps xface-kaplan.ps xface-karlheg.ps xface-kleinpaste.ps \
+xface-kyle.ps xface-love.ps xface-moll.ps xface-niksic.ps \
+xface-olsen.ps xface-patch.ps xface-petersen.ps xface-pjf.ps \
+xface-riocreux.ps xface-schauer.ps xface-simmonmt.ps xface-simmons.ps \
+xface-siu.ps xface-smb.ps xface-sobek.ps xface-thomas.ps \
+xface-valdis.ps xface-verna1.ps xface-verna2.ps xface-yamaoka.ps
+
+SMILIES_PS= BigFace.ps smiley-FaceAngry.ps smiley-FaceDevilish.ps \
+smiley-FaceGoofy.ps smiley-FaceGrinning.ps smiley-FaceHappy.ps \
+smiley-FaceIronic.ps smiley-FaceKOed.ps smiley-FaceNyah.ps \
+smiley-FaceSad.ps smiley-FaceStartled.ps smiley-FaceStraight.ps \
+smiley-FaceTalking.ps smiley-FaceTasty.ps smiley-FaceWinking.ps \
+smiley-FaceWry.ps smiley-FaceYukky.ps smiley-WideFaceAse1.ps \
+smiley-WideFaceAse2.ps smiley-WideFaceAse3.ps smiley-WideFaceSmile.ps \
+smiley-WideFaceWeep.ps
+
+EPS= gnus-big-logo.ps gnus-head.ps
+
+PSFILES= $(SCREEN_PS) $(HERDS_PS) $(ETC_PS) $(PICONS_PS) $(XFACE_PS) \
+$(SMILIES_PS) $(MISC_PS) $(EPS)
+
+SCREEN_PDF= group-topic.pdf group.pdf server.pdf summary-adopt.pdf \
+summary-article-c-ug.pdf summary-article.pdf summary-dummy.pdf \
+summary-empty.pdf summary-none.pdf summary-unthreaded.pdf summary.pdf
+
+HERDS_PDF= gnus-herd-bw.pdf gnus-herd-new.pdf new-herd-1.pdf \
+ new-herd-2.pdf new-herd-3.pdf new-herd-4.pdf \
+new-herd-5.pdf new-herd-6.pdf new-herd-7.pdf new-herd-8.pdf \
+new-herd-9.pdf new-herd-section.pdf new-herd.pdf new-herd2.pdf
+
+MISC_PDF= ered.pdf eseptember.pdf fred.pdf fseptember.pdf larsi.pdf \
+red.pdf september.pdf
+
+ETC_PDF= bar.pdf gnus-group-catchup-current-up.pdf \
+gnus-group-catchup-current.pdf gnus-group-describe-group-up.pdf \
+gnus-group-exit-up.pdf gnus-group-get-new-news-this-group-up.pdf \
+gnus-group-get-new-news-up.pdf gnus-group-kill-group-up.pdf \
+gnus-group-subscribe-up.pdf gnus-group-unsubscribe-up.pdf \
+gnus-summary-caesar-message-up.pdf gnus-summary-cancel-article-up.pdf \
+gnus-summary-catchup-and-exit-up.pdf gnus-summary-catchup-up.pdf \
+gnus-summary-exit-up.pdf gnus-summary-followup-up.pdf \
+gnus-summary-followup-with-original-up.pdf \
+gnus-summary-mail-copy-up.pdf gnus-summary-mail-delete-up.pdf \
+gnus-summary-mail-forward-up.pdf gnus-summary-mail-get-up.pdf \
+gnus-summary-mail-originate-up.pdf gnus-summary-mail-reply-up.pdf \
+gnus-summary-mail-save-up.pdf gnus-summary-next-unread-up.pdf \
+gnus-summary-post-news-up.pdf gnus-summary-prev-unread-up.pdf \
+gnus-summary-reply-up.pdf gnus-summary-reply-with-original-up.pdf \
+gnus-summary-save-article-file-up.pdf gnus-summary-save-article-up.pdf \
+gnus-uu-decode-uu-up.pdf gnus-uu-post-news-up.pdf gnus.pdf
+
+PICONS_PDF= picons-att.pdf picons-berkeley.pdf picons-caltech.pdf \
+picons-canada.pdf picons-cr.pdf picons-cygnus.pdf picons-gnu.pdf \
+picons-gov.pdf picons-laurie.pdf picons-mit.pdf picons-nasa.pdf \
+picons-qmw.pdf picons-rms.pdf picons-ruu.pdf picons-seuu.pdf \
+picons-stanford.pdf picons-sun.pdf picons-ubc.pdf picons-ufl.pdf \
+picons-uio.pdf picons-unit.pdf picons-upenn.pdf picons-wesleyan.pdf \
+picons-yale.pdf
+
+XFACE_PDF= xface-abrahamsen.pdf xface-aichner.pdf xface-blanks.pdf \
+xface-cosgriff.pdf xface-drazen.pdf xface-gertzfield.pdf \
+xface-goldberg.pdf xface-graf.pdf xface-hardaker.pdf xface-hedbor.pdf \
+xface-ingrand.pdf xface-kaplan.pdf xface-karlheg.pdf \
+xface-kleinpaste.pdf xface-kyle.pdf xface-love.pdf xface-moll.pdf \
+xface-niksic.pdf xface-olsen.pdf xface-patch.pdf xface-petersen.pdf \
+xface-pjf.pdf xface-riocreux.pdf xface-schauer.pdf xface-simmonmt.pdf \
+xface-simmons.pdf xface-siu.pdf xface-smb.pdf xface-sobek.pdf \
+xface-thomas.pdf xface-valdis.pdf xface-verna1.pdf xface-verna2.pdf \
+xface-yamaoka.pdf
+
+SMILIES_PDF= BigFace.pdf smiley-FaceAngry.pdf smiley-FaceDevilish.pdf \
+smiley-FaceGoofy.pdf smiley-FaceGrinning.pdf smiley-FaceHappy.pdf \
+smiley-FaceIronic.pdf smiley-FaceKOed.pdf smiley-FaceNyah.pdf \
+smiley-FaceSad.pdf smiley-FaceStartled.pdf smiley-FaceStraight.pdf \
+smiley-FaceTalking.pdf smiley-FaceTasty.pdf smiley-FaceWinking.pdf \
+smiley-FaceWry.pdf smiley-FaceYukky.pdf smiley-WideFaceAse1.pdf \
+smiley-WideFaceAse2.pdf smiley-WideFaceAse3.pdf \
+smiley-WideFaceSmile.pdf smiley-WideFaceWeep.pdf
+
+EPS_PDF= gnus-big-logo.pdf gnus-head.pdf
+
+PDFFILES= $(SCREEN_PDF) $(HERDS_PDF) $(ETC_PDF) $(PICONS_PDF) \
+$(XFACE_PDF) $(SMILIES_PDF) $(MISC_PDF) $(EPS_PDF)
+
+all: $(PSFILES) $(EPS)
+
+pdf: $(PDFFILES)
+
+.ps.pdf:
+ epstopdf $<
+
+.SUFFIXES: .pdf .ps .eps .xbm .xpm .png .tif .gif
+
+clean:
+ rm -f $(PSFILES)
+ rm -f $(PDFFILES)
+
+veryclean: clean
+
+distclean: clean
+
+install:
+
+new-herd-section.ps: $(srcdir)/../herds/new-herd-section.png $(srcdir)/../herds/convol11.pnm
+ pngtopnm $< | pnmscale 4 | pnmconvol $(srcdir)/../herds/convol11.pnm |\
+ ppmtopgm | pnmdepth 255 | \
+ pnmtops -noturn -width 100 -height 100 > $@ || rm -f $@
+
+%.ps: $(srcdir)/../herds/%.png $(srcdir)/../herds/convol5.pnm
+ pngtopnm $< | pnmcrop -white | pnmmargin -white 9 | pnmscale 2 | \
+ pnmconvol $(srcdir)/../herds/convol5.pnm | ppmtopgm | \
+ pnmdepth 255 | pnmtops -width 100 -height 100 -noturn > $@ || rm -f $@
+
+
+%.ps: $(srcdir)/../screen/%.png
+ pngtopnm $< | pnmmargin -black 1 | ppmtopgm | \
+ pnmtops -width 100 -height 100 -noturn > $@ || rm -f $@
+
+larsi.ps: $(srcdir)/../misc/larsi.png
+ pngtopnm $< | ppmtopgm | pnmtops -noturn > $@ || rm -f $@
+
+september.ps: $(srcdir)/../misc/eseptember.tif
+ tifftopnm $< | pnmscale 4 | ppmtopgm | \
+ pnmtops -noturn -width 100 -height 100 > $@ || rm -f $@
+
+red.ps: $(srcdir)/../misc/ered.tif
+ tifftopnm $< | pnmscale 2 | ppmtopgm | \
+ pnmtops -noturn -width 100 -height 100 > $@ || rm -f $@
+
+%.ps: $(srcdir)/../misc/%.tif
+ tifftopnm $< | pnmscale 2 | ppmtopgm | \
+ pnmtops -noturn -width 100 -height 100 > $@ || rm -f $@
+
+%.ps: $(srcdir)/../etc/%.xpm
+ xpmtoppm $< | ppmtopgm | pnmdepth 255 | \
+ pnmtops -noturn > $@ || rm -f $@
+
+picons-%.ps: $(srcdir)/../picons/%.xbm
+ xbmtopbm $< | pnmtops -noturn > $@ || rm -f $@
+
+picons-%.ps: $(srcdir)/../picons/%.png
+ pngtopnm $< | ppmtopgm | pnmtops -noturn > $@ || rm -f $@
+
+xface-%.ps: $(srcdir)/../xface/%.png
+ pngtopnm $< | ppmtopgm | pnmtops -noturn > $@ || rm -f $@
+
+%.ps: $(srcdir)/../smilies/%.tif
+ tifftopnm $< | ppmtopgm | pnmtops > $@ || rm -f $@
+
+smiley-%.ps: $(srcdir)/../smilies/%.xpm
+ sed "s/none/#FFFFFF/" $< | xpmtoppm | ppmtopgm | pnmdepth 255 | \
+ pnmtops > $@ || rm -f $@
+
+smiley-%.ps: $(srcdir)/../smilies/%.xbm
+ xbmtopbm $< | pnmdepth 255 | pnmtops > $@ || rm -f $@
+
+%.ps: $(srcdir)/%.eps
+ cp $< $@
+
+Makefile: $(srcdir)/Makefile.in ../../config.status
+ cd ../.. \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+# 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:
%%ColorUsage: B & W
%%TileBox: 0 0 890.3 909.7
%%EndComments
-%%BeginProcSet:Adobe_Illustrator_1.1 0 0
% Copyright 1992 Corel Corporation.
% All rights reserved.
%%ColorUsage: B & W
%%TileBox: 0 0 430.6 312.5
%%EndComments
-%%BeginProcSet:Adobe_Illustrator_1.1 0 0
% Copyright 1992 Corel Corporation.
% All rights reserved.
-% -*- latex -*-
-% Reference Card for (ding) Gnus 5.8.x: to be processed with LaTeX2e
+% Reference Card for Oort Gnus: to be processed with LaTeX2e
\documentclass{article}
+
+\usepackage{supertabular}
+
\def\Guide{Card}\def\guide{card}
\def\logoscale{0.25}
-\textwidth 7.26in \textheight 10in \topmargin -1.0in
+\setlength{\textwidth}{7.26in} \setlength{\textheight}{10in}
+\setlength{\topmargin}{-1.0in}
% the same settings work for A4, although there is a bit of space at the
% top and bottom of the page.
-\oddsidemargin -0.5in \evensidemargin -0.5in
+\setlength{\oddsidemargin}{-0.5in} \setlength{\evensidemargin}{-0.5in}
+
+\usepackage{epsfig}
% README:
% *** purpose
-% this was originally thought of as a reference card, but as it is now 5+
-% pages long, I doubt that it is more useful than the online-help. It helped
+% this was originally thought of as a reference card (but as it is now 5+
+% pages long, it may not be more useful than the online-help). It helps
% to get an overview for the Gnus-functionality.
%
% *** files
-% refcard.tex (this file), gnusref.tex ("include"-file) and gnuslogo.refcard
-% (Gnus logo).
+% refcard.tex (this file), gnusref.tex ("include"-file) and
+% gnuslogo-refcard.eps (Gnus logo).
%
% *** printing (about 5 pages now: write me if you can make it shorter..)
% if you are using latex-mode, you do C-c C-f (process with latex),
\newlength{\logowidth} \setlength{\logowidth}{6.861in}
\newlength{\logoheight} \setlength{\logoheight}{7.013in}
-\def\progver{5.8}\def\refver{5.8-4} % program and refcard versions
-\def\date{July 27th, 2000}
-\def\author{Vladimir Alexiev $<$vladimir@cs.ualberta.ca$>$}
+\def\progver{5.10}\def\refver{5.10-1} % program and refcard versions
+\def\date{Oct 13th, 2001}
+\def\author{Gnus Bugfixing Girls + Boys $<$bugs@gnus.org$>$}
\raggedbottom\raggedright
\twocolumn
+% use \tiny to shrink it to 4 pages (needs a high-resaoultion printer, though)
%\tiny
\scriptsize
\pagestyle{plain}
\end{document}
-
+%%% Local Variables:
+%%% mode: latex
+%%% End:
--- /dev/null
+\input texinfo @c -*-texinfo-*-
+
+@setfilename sieve
+@settitle Emacs Sieve Manual
+@synindex fn cp
+@synindex vr cp
+@synindex pg cp
+@dircategory Emacs
+@direntry
+* Sieve: (sieve). Managing Sieve scripts in Emacs.
+@end direntry
+@iftex
+@finalout
+@end iftex
+@setchapternewpage odd
+
+@ifnottex
+
+This file documents the Emacs Sieve package.
+
+Copyright (C) 2001 Free Software Foundation, Inc.
+
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.1 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, with the Front-Cover texts being ``A GNU
+Manual'', and with the Back-Cover Texts as in (a) below. A copy of the
+license is included in the section entitled ``GNU Free Documentation
+License'' in the Emacs manual.
+
+(a) The FSF's Back-Cover Text is: ``You have freedom to copy and modify
+this GNU Manual, like GNU software. Copies published by the Free
+Software Foundation raise funds for GNU development.''
+
+This document is part of a collection distributed under the GNU Free
+Documentation License. If you want to distribute this document
+separately from the collection, you can do so by adding a copy of the
+license to the document, as described in section 6 of the license.
+@end ifnottex
+
+@tex
+
+@titlepage
+@title Emacs Sieve Manual
+
+@author by Simon Josefsson
+@page
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 2001 Free Software Foundation, Inc.
+
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.1 or
+any later version published by the Free Software Foundation; with the
+Invariant Sections being none, with the Front-Cover texts being ``A GNU
+Manual'', and with the Back-Cover Texts as in (a) below. A copy of the
+license is included in the section entitled ``GNU Free Documentation
+License'' in the Emacs manual.
+
+(a) The FSF's Back-Cover Text is: ``You have freedom to copy and modify
+this GNU Manual, like GNU software. Copies published by the Free
+Software Foundation raise funds for GNU development.''
+
+This document is part of a collection distributed under the GNU Free
+Documentation License. If you want to distribute this document
+separately from the collection, you can do so by adding a copy of the
+license to the document, as described in section 6 of the license.
+@end titlepage
+@page
+
+@end tex
+
+@node Top
+@top Sieve Support for Emacs
+
+This manual documents the Emacs Sieve package.
+
+It is intended as a users manual for Sieve Mode and Manage Sieve, and
+as a reference manual for the @samp{sieve-manage} protocol Emacs Lisp
+API.
+
+Sieve is a language for server-side filtering of mail. The language
+is documented in RFC 3028. This manual does not attempt to document
+the language, so keep RFC 3028 around.
+
+A good online Sieve resources is @uref{http://www.cyrusoft.com/sieve/}.
+
+@menu
+* Installation:: Getting ready to use the package.
+* Sieve Mode:: Editing Sieve scripts.
+* Managing Sieve:: Managing Sieve scripts on a remote server.
+* Examples :: A few Sieve code snippets.
+* Manage Sieve API :: Interfacing to the Manage Sieve Protocol API.
+* Standards:: A summary of RFCs and working documents used.
+* Index:: Function and variable index.
+@end menu
+
+
+@node Installation
+@chapter Installation
+@cindex Install
+@cindex Setup
+
+The Sieve package should come with your Emacs version, and should be
+ready for use directly.
+
+However, to manually set up the package you can put the following
+commands in your @code{~/.emacs}:
+
+@lisp
+(autoload 'sieve-mode "sieve-mode")
+@end lisp
+@lisp
+(setq auto-mode-alist (cons '("\\.si\\(v\\|eve\\)\\'" . sieve-mode)
+ auto-mode-alist))
+@end lisp
+
+
+@node Sieve Mode
+@chapter Sieve Mode
+
+Sieve mode provides syntax-based indentation, font-locking support and
+other handy functions to make editing Sieve scripts easier.
+
+Use @samp{M-x sieve-mode} to switch to this major mode. This command
+runs the hook @code{sieve-mode-hook}.
+
+@vindex sieve-mode-map
+@vindex sieve-mode-syntax-table
+Sieve mode is derived from @code{c-mode}, and is very similar except
+for the syntax of comments. The keymap (@code{sieve-mode-map}) is
+inherited from @code{c-mode}, as are the the variables for customizing
+indentation. Sieve mode has its own abbrev table
+(@code{sieve-mode-abbrev-table}) and syntax table
+(@code{sieve-mode-syntax-table}).
+
+In addition to the editing utility functions, Sieve mode also contains
+bindings to manage Sieve scripts remotely. @pxref{Managing Sieve}.
+
+@table @kbd
+
+@item C-c RET
+@kindex C-c RET
+@findex sieve-manage
+@cindex manage remote sieve script
+Open a connection to a remote server using the Managesieve protocol.
+
+@item C-c C-l
+@kindex C-c C-l
+@findex sieve-upload
+@cindex upload sieve script
+Upload the Sieve script to the currently open server.
+
+@end table
+
+
+@node Managing Sieve
+@chapter Managing Sieve
+
+Manage Sieve is a special mode used to display Sieve scripts available
+on a remote server. It can be invoked with @kbd{M-x sieve-manage
+RET}, which queries the user for a server and if necessary, user
+credentials to use.
+
+When a server has been succesfully contacted, the Manage Sieve buffer
+looks something like:
+
+@example
+Server : mailserver:2000
+
+2 scripts on server, press RET on a script name edits it, or
+press RET on <new script> to create a new script.
+ <new script>
+ ACTIVE .sieve
+ template.siv
+@end example
+
+One of the scripts are highlighted, and standard point navigation
+commands (@kbd{<up>}, @kbd{<down>} etc) can be used to navigate the
+list.
+
+The following commands are available in the Manage Sieve buffer:
+
+@table @kbd
+
+@item m
+@kindex m
+@findex sieve-activate
+Activates the currently highlighted script.
+
+@item u
+@kindex u
+@findex sieve-deactivate
+Deactivates the currently highlighted script.
+
+@item C-M-?
+@kindex C-M-?
+@findex sieve-deactivate-all
+Deactivates all scripts.
+
+@item r
+@kindex r
+@findex sieve-remove
+Remove currently highlighted script.
+
+@item RET
+@item mouse-2
+@item f
+@kindex RET
+@kindex mouse-2
+@kindex f
+@findex sieve-edit-script
+Bury the server buffer and download the currently highlighted script
+into a new buffer for editing in Sieve mode (@pxref{Sieve Mode}).
+
+@item o
+@kindex o
+@findex sieve-edit-script-other-window
+Create a new buffer in another window containing the currently
+highlighted script for editing in Sieve mode (@pxref{Sieve Mode}).
+
+@item q
+@kindex q
+@findex sieve-bury-buffer
+Bury the Manage Sieve buffer without closing the connection.
+
+@item ?
+@item h
+@kindex ?
+@kindex h
+@findex sieve-help
+Displays help in the minibuffer.
+
+@end table
+
+@node Examples
+@chapter Examples
+
+If you are not familiar with Sieve, this chapter contains a few simple
+code snippets that you can cut'n'paste and modify at will, until you
+feel more comfortable with the Sieve language to write the rules from
+scratch.
+
+The following complete Sieve script places all messages with a matching
+@samp{Sender:} header into the given mailbox. Many mailing lists uses
+this format. The first line makes sure your Sieve server understands
+the @code{fileinto} command.
+
+@example
+require "fileinto";
+
+if address "sender" "owner-w3-beta@@xemacs.org" @{
+ fileinto "INBOX.w3-beta";
+@}
+@end example
+
+A few mailing lists do not use the @samp{Sender:} header, but does
+contain some unique identifier in some other header. The following is
+not a complete script, it assumes that @code{fileinto} has already been
+required.
+
+@example
+if header :contains "Delivered-To" "auc-tex@@sunsite.dk" @{
+ fileinto "INBOX.auc-tex";
+@}
+@end example
+
+At last, we have the hopeless mailing lists that does not have any
+unique identifier and you are forced to match on the @samp{To:} and
+@samp{Cc} headers. As before, this snippet assumes that @code{fileinto}
+has been required.
+
+@example
+if address ["to", "cc"] "kerberos@@mit.edu" @{
+ fileinto "INBOX.kerberos";
+@}
+@end example
+
+@node Manage Sieve API
+@chapter Manage Sieve API
+
+The @file{sieve-manage.el} library contains low-level functionality
+for talking to a server with the @sc{managesieve} protocol.
+
+A number of user-visible variables exist, which all can be customized
+in the @code{sieve} group (@kbd{M-x customize-group RET sieve RET}):
+
+@table @code
+
+@item sieve-manage-default-user
+@vindex sieve-manage-default-user
+Sets the default username.
+
+@item sieve-manage-default-port
+@vindex sieve-manage-default-port
+Sets the default port to use, the suggested port number is @code{2000}.
+
+@item sieve-manage-log
+@vindex sieve-manage-log
+If non-nil, should be a string naming a buffer where a protocol trace
+is dumped (for debugging purposes).
+
+@end table
+
+The API functions include:
+
+@table @code
+
+@item sieve-manage-open
+@findex sieve-manage-open
+Open connection to managesieve server, returning a buffer to be used
+by all other API functions.
+
+@item sieve-manage-opened
+@findex sieve-manage-opened
+Check if a server is open or not.
+
+@item sieve-manage-close
+@findex sieve-manage-close
+Close a server connection.
+
+@item sieve-manage-authenticate
+@findex sieve-manage-authenticate
+Authenticate to the server.
+
+@item sieve-manage-capability
+@findex sieve-manage-capability
+Return a list of capabilities the server support.
+
+@item sieve-manage-listscripts
+@findex sieve-manage-listscripts
+List scripts on the server.
+
+@item sieve-manage-havespace
+@findex sieve-manage-havespace
+Returns non-nil iff server have roam for a script of given size.
+
+@item sieve-manage-getscript
+@findex sieve-manage-getscript
+Download script from server.
+
+@item sieve-manage-putscript
+@findex sieve-manage-putscript
+Upload script to server.
+
+@item sieve-manage-setactive
+@findex sieve-manage-setactive
+Indicate which script on the server should be active.
+
+@end table
+
+@node Standards
+@chapter Standards
+
+The Emacs Sieve package implements all or parts of a small but
+hopefully growing number of RFCs and drafts documents. This chapter
+lists the relevant ones. They can all be fetched from
+@uref{http://quimby.gnus.org/notes/}.
+
+@table @dfn
+
+@item RFC3028
+Sieve: A Mail Filtering Language.
+
+@item draft-martin-managesieve-03
+A Protocol for Remotely Managing Sieve Scripts
+
+@end table
+
+
+@node Index
+@chapter Index
+@printindex cp
+
+@summarycontents
+@contents
+@bye
+
+@c End:
--- /dev/null
+/* XPM */
+static char * image_name[] = {
+"12 12 5 1",
+" c none",
+". c #FFFF00 s flesh",
+"X c #000000000000 s features",
+"E c #000000000000 s circle",
+"o c #555555555555 s tongue",
+" EEEE ",
+" EE....EE ",
+" E........E ",
+" E.X....X.E ",
+"E...X..X...E",
+"E...X..X...E",
+"E..........E",
+"E...XXXX...E",
+" E.X....X.E ",
+" E........E ",
+" EE....EE ",
+" EEEE ....",
--- /dev/null
+/* XPM */
+static char * image_name[] = {
+"12 12 5 1",
+" c none",
+". c #FFFF00 s flesh",
+"X c #000000000000 s features",
+"E c #000000000000 s circle",
+"o c #555555555555 s tongue",
+"..E EEEE E..",
+"E..E....E..E",
+" E........E ",
+" E.. .....E ",
+"E..XX..XX..E",
+"E..........E",
+"E.X......X.E",
+"E..X....X..E",
+" E..XXXX..E ",
+" E........E ",
+" EE....EE ",
+" EEEE ....",
--- /dev/null
+/* XPM */
+static char * image_name[] = {
+"12 12 5 1",
+" c none",
+". c #FFFF00 s flesh",
+"X c #000000000000 s features",
+"E c #000000000000 s circle",
+"o c #555555555555 s tongue",
+" EEEE ",
+" EE....EE ",
+" E........E ",
+" E..X..X..E ",
+"E...X..X...E",
+"E..........E",
+"E.X......X.E",
+"E.XXXXXXXX.E",
+" E........E ",
+" E........E ",
+" EE....EE ",
+" EEEE ....",
--- /dev/null
+/* XPM */
+static char * image_name[] = {
+"12 12 5 1",
+" c none",
+". c #FFFF00 s flesh",
+"X c #000000000000 s features",
+"E c #000000000000 s circle",
+"o c #555555555555 s tongue",
+" EEEE ",
+" EE....EE ",
+" E........E ",
+" E..X..X..E ",
+"E...X..X...E",
+"E..........E",
+"E..XXXXXX..E",
+"E..X....X..E",
+" E..X..X..E ",
+" E...XX...E ",
+" EE....EE ",
+" EEEE ....",
--- /dev/null
+/* XPM */
+static char * image_name[] = {
+"12 12 5 1",
+" c #FFFFFF",
+". c #FFFF00 s flesh",
+"X c #000000000000 s features",
+"E c #000000000000 s circle",
+"o c #555555555555 s tongue",
+" EEEE ",
+" EE....EE ",
+" E........E ",
+" E..X..X..E ",
+"E...X..X...E",
+"E..........E",
+"E.X......X.E",
+"E..XXXXXX..E",
+" E..XXXX..E ",
+" E........E ",
+" EE....EE ",
+" EEEE ....",
--- /dev/null
+/* XPM */
+static char * image_name[] = {
+"12 12 5 1",
+" c none",
+". c #FFFF00 s flesh",
+"X c #000000000000 s features",
+"E c #000000000000 s circle",
+"o c #555555555555 s tongue",
+" EEEE ",
+" EE....EE ",
+" E........E ",
+" E..X..X..E ",
+"E...X..X...E",
+"E..........E",
+"E........X.E",
+"E...XXXXX..E",
+" E.X......E ",
+" E........E ",
+" EE....EE ",
+" EEEE ....",
--- /dev/null
+/* XPM */
+static char * image_name[] = {
+"12 12 5 1",
+" c none",
+". c #FFFF00 s flesh",
+"X c #000000000000 s features",
+"E c #000000000000 s circle",
+"o c #555555555555 s tongue",
+" EEEE ",
+" EE....EE ",
+" E........E ",
+" E.X.XX.X.E ",
+"E...X..X...E",
+"E..X.XX.X..E",
+"E..........E",
+"E..........E",
+" E.XXXXXX.E ",
+" E........E ",
+" EE....EE ",
+" EEEE ....",
--- /dev/null
+/* XPM */
+static char * image_name[] = {
+"12 12 5 1",
+" c none",
+". c #FFFF00 s flesh",
+"X c #000000000000 s features",
+"E c #000000000000 s circle",
+"o c #555555555555 s tongue",
+" EEEE ",
+" EE....EE ",
+" E........E ",
+" E........E ",
+"E..XX..XX..E",
+"E..........E",
+"E..........E",
+"E...XXXX...E",
+" E..oooX..E ",
+" E...oo...E ",
+" EE.Xo.EE ",
+" EEEE .Xo.",
--- /dev/null
+/* XPM */
+static char * image_name[] = {
+"12 12 5 1",
+" c none",
+". c #FFFF00 s flesh",
+"X c #000000000000 s features",
+"E c #000000000000 s circle",
+"o c #555555555555 s tongue",
+" EEEE ",
+" EE....EE ",
+" E........E ",
+" E..X..X..E ",
+"E...X..X...E",
+"E..........E",
+"E..........E",
+"E...XXXX...E",
+" E.X....X.E ",
+" EX......XE ",
+" EE....EE ",
+" EEEE ....",
--- /dev/null
+/* XPM */
+static char * image_name[] = {
+"12 12 5 1",
+" c none",
+". c #FFFF00 s flesh",
+"X c #000000000000 s features",
+"E c #000000000000 s circle",
+"o c #555555555555 s tongue",
+" EEEE ",
+" EE....EE ",
+" E........E ",
+" E..X..X..E ",
+"E...X..X...E",
+"E..........E",
+"E...XXXX...E",
+"E..X....X..E",
+" E.X....X.E ",
+" E..XXXX..E ",
+" EE....EE ",
+" EEEE ....",
--- /dev/null
+/* XPM */
+static char * image_name[] = {
+"12 12 5 1",
+" c none",
+". c #FFFF00 s flesh",
+"X c #000000000000 s features",
+"E c #000000000000 s circle",
+"o c #555555555555 s tongue",
+" EEEE ",
+" EE....EE ",
+" E........E ",
+" E..X..X..E ",
+"E...X..X...E",
+"E..........E",
+"E..........E",
+"E...XXXX...E",
+" E........E ",
+" E........E ",
+" EE....EE ",
+" EEEE ....",
--- /dev/null
+/* XPM */
+static char * image_name[] = {
+"12 12 5 1",
+" c none",
+". c #FFFF00 s flesh",
+"X c #000000000000 s features",
+"E c #000000000000 s circle",
+"o c #555555555555 s tongue",
+" EEEE ",
+" EE....EE ",
+" E........E ",
+" E..X..X..E ",
+"E...X..X...E",
+"E..........E",
+"E..........E",
+"E...XXXXX..E",
+" E....XXX.E ",
+" E....XX..E ",
+" EE....EE ",
+" EEEE ....",
--- /dev/null
+/* XPM */
+static char * image_name[] = {
+"12 12 5 1",
+" c none",
+". c #FFFF00 s flesh",
+"X c #000000000000 s features",
+"E c #000000000000 s circle",
+"o c #555555555555 s tongue",
+" EEEE ",
+" EE....EE ",
+" E........E ",
+" E..X..X..E ",
+"E...X..X...E",
+"E..........E",
+"E...o......E",
+"E..ooo.....E",
+" E.XXXXX..E ",
+" E........E ",
+" EE....EE ",
+" EEEE ....",
--- /dev/null
+/* XPM */
+static char * image_name[] = {
+"12 12 5 1",
+" c none",
+". c #FFFF00 s flesh",
+"X c #000000000000 s features",
+"E c #000000000000 s circle",
+"o c #555555555555 s tongue",
+" EEEE ",
+" EE....EE ",
+" E........E ",
+" E..X.....E ",
+"E...X.XXX..E",
+"E..........E",
+"E.X......X.E",
+"E..XXXXXX..E",
+" E..XXXX..E ",
+" E........E ",
+" EE....EE ",
+" EEEE ....",
--- /dev/null
+/* XPM */
+static char * image_name[] = {
+"12 12 5 1",
+" c none",
+". c #FFFF00 s flesh",
+"X c #000000000000 s features",
+"E c #000000000000 s circle",
+"o c #555555555555 s tongue",
+" EEEE ",
+" EE....EE ",
+" E........E ",
+" E..X..X..E ",
+"E...X..X...E",
+"E..........E",
+"E..........E",
+"E.....XXX..E",
+" E..XX....E ",
+" E....XX..E ",
+" EE....EE ",
+" EEEE ....",
--- /dev/null
+/* XPM */
+static char * image_name[] = {
+"12 12 5 1",
+" c none",
+". c #FFFF00 s flesh",
+"X c #000000000000 s features",
+"E c #000000000000 s circle",
+"o c #555555555555 s tongue",
+" EEEE ",
+" EE....EE ",
+" E........E ",
+" E.X....X.E ",
+"E...X..X...E",
+"E..........E",
+"E..........E",
+"E..XXXXX...E",
+" E..oooX..E ",
+" E...oo...E ",
+" EE.Xo.EE ",
+" EEEE .Xo.",
--- /dev/null
+#define Face_ase_width 24
+#define Face_ase_height 16
+static char Face_ase_bits[] = {
+ 0x00,0x00,0x00,
+ 0xf8,0xc1,0x0f,
+ 0x04,0x22,0x10,
+ 0x00,0x00,0x00,
+ 0xf0,0xc0,0x03,
+ 0x68,0xa1,0x05,
+ 0x68,0xa1,0x05,
+ 0x68,0xa1,0x05,
+ 0xf0,0xc0,0x23,
+ 0x00,0x00,0x20,
+ 0x00,0x00,0x50,
+ 0x50,0x40,0x52,
+ 0x00,0x00,0x50,
+ 0x20,0x91,0x20,
+ 0x00,0x0e,0x00,
+ 0x00,0x00,0x00};
--- /dev/null
+#define Face_ase2_width 32
+#define Face_ase2_height 16
+static char Face_ase2_bits[] = {
+ 0x00,0x00,0x00,0x00,
+ 0xf0,0x83,0x1f,0x00,
+ 0x08,0x44,0x20,0x00,
+ 0x00,0x00,0x00,0x00,
+ 0xe0,0x81,0x07,0x00,
+ 0xd0,0x42,0x0b,0x00,
+ 0xd0,0x42,0x0b,0x00,
+ 0xd0,0x42,0x0b,0x00,
+ 0xe0,0x81,0x87,0x10,
+ 0x00,0x00,0x80,0x10,
+ 0x00,0x00,0x40,0x29,
+ 0xa0,0x80,0x44,0x29,
+ 0x00,0x00,0x40,0x29,
+ 0x40,0x22,0x81,0x10,
+ 0x00,0x1c,0x00,0x00,
+ 0x00,0x00,0x00,0x00};
--- /dev/null
+#define Face_ase3_width 24
+#define Face_ase3_height 16
+static char Face_ase3_bits[] = {
+ 0x00,0x00,0x00,
+ 0xf8,0xc1,0x0f,
+ 0x04,0x22,0x10,
+ 0x00,0x00,0x00,
+ 0x18,0x00,0x07,
+ 0xe0,0xe0,0x00,
+ 0xfc,0xf3,0x0f,
+ 0xc0,0xe1,0x00,
+ 0x38,0x00,0x27,
+ 0x00,0x00,0x20,
+ 0x00,0x00,0x50,
+ 0x50,0x40,0x52,
+ 0x00,0x00,0x50,
+ 0x20,0x91,0x20,
+ 0x00,0x0e,0x00,
+ 0x00,0x00,0x00
+};
--- /dev/null
+#define Face_smile_width 24
+#define Face_smile_height 16
+static char Face_smile_bits[] = {
+ 0x00,0x00,0x00,
+ 0xf8,0xc1,0x0f,
+ 0x04,0x22,0x10,
+ 0x00,0x00,0x00,
+ 0xf0,0xc0,0x07,
+ 0x68,0xa1,0x09,
+ 0x68,0xa1,0x09,
+ 0x68,0xa1,0x09,
+ 0xf0,0xc0,0x07,
+ 0x00,0x00,0x00,
+ 0x00,0x00,0x00,
+ 0x50,0x80,0x04,
+ 0x00,0x00,0x00,
+ 0x20,0x22,0x01,
+ 0x00,0x1c,0x00,
+ 0x00,0x00,0x00};
--- /dev/null
+#define Face_weep_width 24
+#define Face_weep_height 16
+static char Face_weep_bits[] = {
+ 0x1c,0x00,0x3c,
+ 0xe2,0x80,0x43,
+ 0x00,0x63,0x00,
+ 0x18,0x00,0x18,
+ 0x60,0x00,0x07,
+ 0x80,0xe3,0x00,
+ 0xfc,0xf7,0x3f,
+ 0x80,0xe3,0x00,
+ 0x60,0x00,0x07,
+ 0x58,0x00,0x1a,
+ 0x40,0x00,0x02,
+ 0xa0,0x00,0x05,
+ 0xa0,0x00,0x05,
+ 0xa0,0x1c,0x05,
+ 0x40,0x22,0x02,
+ 0x00,0x00,0x00
+};
#!/bin/sh
match='M-x |(Group)|(Summary)|(Article)|(Server)|(Browse)|(Post)|(Mail)|(Score)|(Binary)|(Topic)|(Pick)'
-fun='{gnus-|{nn.*-|{grouplens-'
+fun='\{gnus-|\{nn.*-|\{grouplens-'
egrep "$match" gnus.idx > gnus.kidx
egrep "$fun" gnus.idx > gnus.gidx
egrep -v "$match|$fun" gnus.idx > gnus.cidx
"Translate."
(interactive)
(latexi-translate-file "gnus")
- (latexi-translate-file "gnus-faq"))
+ (latexi-translate-file "gnus-faq")
+ (latexi-translate-file "message" t)
+ (latexi-translate-file "emacs-mime" t)
+ (latexi-translate-file "sieve" t))
-(defun latexi-translate-file (file)
+(defun latexi-translate-file (file &optional as-a-chapter)
"Translate file a LaTeX file."
(let ((item-string "")
(item-stack nil)
(latexi-translate-string "%@{" "\\gnuspercent{}\\gnusbraceleft{}")
(latexi-translate-string "%@}" "\\gnuspercent{}\\gnusbraceright{}")
(latexi-translate-string "%1@{" "\\gnuspercent{}1\\gnusbraceright{}")
+ (latexi-translate-string "@*" "\\newline{}")
+ (latexi-translate-string "S@{" "S\\gnusbraceleft{}")
+ (latexi-translate-string "@code{\\222}" "@code{\\gnusbackslash{}222}")
+ (latexi-translate-string "@code{\\264}" "@code{\\gnusbackslash{}264}")
+ (latexi-translate-string "@samp{\\Deleted}" "@samp{\\gnusbackslash{}Deleted}")
+ (latexi-translate-string "@samp{\\Seen}" "@samp{\\gnusbackslash{}Seen}")
; (while (re-search-forward "{\"[^\"]*\\(\\\\\\)[^\"]*\"}\\\\" nil t)
; (replace-match "\\verb+\\\\+ " t t))
(while (not (zerop (decf times)))
"ifnottex" "direntry"))
(latexi-discard-until command))
((member command '("subsection" "subsubsection"))
- (latexi-switch-line command arg))
+ (if as-a-chapter
+ (latexi-switch-line (format "sub%s" command) arg)
+ (latexi-switch-line command arg)))
((member command '("chapter"))
- (latexi-switch-line
- (format
- "gnus%s{\\epsfig{figure=tmp/new-herd-%d.ps,scale=.5}}"
- command (incf chapter))
- arg))
+ (if (string-match "Index" arg)
+ (latexi-strip-line)
+ (if as-a-chapter
+ (latexi-switch-line "gnussection" arg)
+ (latexi-switch-line
+ (format
+ "gnus%s{%s}" command
+ (format "\\epsfig{figure=ps/new-herd-%d,scale=.5}"
+ (if (> (incf chapter) 9) 9 chapter)))
+ arg))))
((member command '("section"))
- (latexi-switch-line (format "gnus%s" command) arg))
+ (if as-a-chapter
+ (latexi-switch-line "subsection" arg)
+ (latexi-switch-line (format "gnus%s" command) arg)))
((member command '("cindex" "findex" "kindex" "vindex"))
(latexi-index-command command arg))
((member command '("*"))
(replace-match "" t t))
((equal command "node")
(latexi-strip-line)
- (insert (format "\\label{%s}\n" arg)))
+ (unless (string-match "Index" arg)
+ (insert (format "\\label{%s}\n" arg))))
((equal command "contents")
(latexi-strip-line)
;;(insert (format "\\tableofcontents\n" arg))
(insert "duppat{}"))
((equal command "settitle")
(latexi-strip-line)
- (insert (format "\\newcommand{\\gnustitlename}{%s}\n" arg)))
+ (if (not as-a-chapter)
+ (insert
+ (format "\\newcommand{\\gnustitlename}{%s}\n" arg))))
((equal command "title")
(latexi-strip-line)
(insert (format "\\gnustitlename{%s}\n" arg)))
(delete-char 1))
((equal command "include")
(latexi-strip-line)
- (insert "\\input{gnus-faq.latexi}\n"))
+ (string-match "\\.texi" arg)
+ (insert (format "\\input{%s.latexi}\n"
+ (substring arg 0 (match-beginning 0)))))
+ ((equal command "noindent")
+ (latexi-strip-line)
+ (insert "\\noindent\n"))
((equal command "printindex")
(latexi-strip-line)
;;(insert
;; "\\begin{theindex}\\input{gnus.%s}\\end{theindex}\n" arg))
)
(t
- (error "Unknown command: %s" command))))
+ (error "Unknown command (line %d): %s"
+ (save-excursion
+ (widen)
+ (1+ (count-lines (point-min) (progn
+ (beginning-of-line)
+ (point)))))
+ command))))
;; These are commands with {}.
(setq arg (match-string 5))
(cond
((member command '("anchor"))
(latexi-strip-line))
- ((member command '("xref" "pxref"))
+ ((member command '("ref" "xref" "pxref"))
(latexi-exchange-command (concat "gnus" command) arg))
((member command '("sc" "file" "dfn" "emph" "kbd" "uref"
"code" "samp" "var" "strong" "i"
(delete-char 2)
(insert "duppat{}"))
(t
- (error "Unknown command: %s" command))))))
+ (error "Unknown command (line %d): %s"
+ (save-excursion
+ (widen)
+ (1+ (count-lines (point-min) (progn
+ (beginning-of-line)
+ (point)))))
+ command))))))
(latexi-translate-string "$" "\\gnusdollar{}")
(latexi-translate-string "&" "\\gnusampersand{}")
(latexi-translate-string "%" "\\gnuspercent{}")
;; Also know as the "wish list". Some are done. For the others, no
;; promise when to be implemented.
+* Speed up sorting in summary buffer if there is a limit.
+
+ Suggested by Daniel Ortmann <ortmann@isl.net>.
+
+* Investigate the memory usage of Gnus.
+
+ But it does seem strange that Gnus would use some 15meg for this. I
+ think that is worth investigating. I suspect that bugs or bad
+ design are causing waste; they could be in Gnus, or in Emacs. -- RMS
+
+* Google group digest
+
+ The result of Google group search return a thread. Is it a digest
+ format?
+
+* NOV caching.
+
+ Implement NOV caching with Gnus Agent.
+
+* Multiple charsets for topic names.
+
+ [Done]
+
+* Allow specification of server in Newsgroups header
+
+ [Kai wrote]
+
+ WIBNI I could put `Newsgroups: nntp+quimby:bla' into a message and
+ Gnus would know to post this message on my server `nntp:quimby' into
+ the group bla? I think this would be way cool.
+
+ But Gnus would have to rewrite the Newsgroups header before actually
+ sending the posting.
+
+ Thanks for Micha Wiedenmann for this suggestion.
+
* Understand mail-user-agent. Maybe gnus-mail-user-agent.
[Done]
* Be able to run `J u' from summary buffers.
+ [Done]
+
* Solve the halting problem.
\f