From: yamaoka Date: Sun, 6 Jan 2002 22:11:39 +0000 (+0000) Subject: Importing Oort Gnus v0.04. X-Git-Tag: ognus-0_04~1 X-Git-Url: http://git.chise.org/gitweb/?a=commitdiff_plain;h=3738187cad20787b5b99c4061256e30e19ee721a;p=elisp%2Fgnus.git- Importing Oort Gnus v0.04. --- diff --git a/.cvsignore b/.cvsignore index 9c59f23..75f639b 100644 --- a/.cvsignore +++ b/.cvsignore @@ -6,3 +6,4 @@ diff-lisp.el diffit makepub cvs-access +cup-page diff --git a/ChangeLog b/ChangeLog index ec85b11..7451506 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,94 @@ +2001-12-18 Josh Huber + + * ChangeLog, todo: (oops) changed buffer-file-coding-system back + to coding. + +2001-12-18 Kai Gro,A_(Bjohann + + * make-x.bat: Ensure nonempty variable value. Reported by Frank + Haun . + +2001-12-18 01:00:00 ShengHuo ZHU + + * ChangeLog, todo: Add `coding'. + +2001-12-17 Josh Huber + + * ChangeLog: changed coding to buffer-file-coding-system + * todo: same + +2001-12-10 Kai Gro,A_(Bjohann + + * make-x.bat: Code cleanup. Fix a bug with "/copy". From Frank + Schmitt . + +2001-11-26 Kai Gro,A_(Bjohann + + * make-x.bat: Use parameter "/copy" rather than "copy" for increased + dwimishness for old-time DOS users. From Frank Schmitt + . + +2001-11-15 Simon Josefsson + + * etc/gnus/unimportant.xpm, etc/gnus/important.xpm: New files. + +2001-11-11 Simon Josefsson + + * make-x.bat: Don't use -nw. Suggested by Frank Haun + . + +2001-11-01 07:00:00 ShengHuo ZHU + + * etc/smilies/blink.xpm: New set of xpm. From Oliver Scholz + . + +2001-10-29 Per Abrahamsen + + * etc/smilies/sad.pbm: New bitmap. + * etc/smilies/blink.pbm: Ditto. + Contributed by Kim F. Storm . + +2001-10-19 Kai Gro,A_(Bjohann + From Frank Schmitt . + + * make-x.bat: Use correct directory structure for XEmacs on Windows. + +2001-10-06 08:00:00 ShengHuo ZHU + + * Makefile.in (uninstall): Add. + + * etc/Makefile.in (uninstall): Add. + +2001-09-27 14:00:00 ShengHuo ZHU + + * aclocal.m4 (GNUS_CHECK_FONTS): Typo. Use /dev/null as latex input. + +2001-09-27 09:00:00 ShengHuo ZHU + + * aclocal.m4, configure.in: Check commercial fonts. + +2001-09-24 19:00:00 ShengHuo ZHU + + * configure.in: Generate texi/ps/Makefile. + +2001-09-21 Kai Gro,A_(Bjohann + + * make.bat: Use parameter "/copy" rather than "copy" for increased + dwimishness for old-time DOS users. + +2001-09-18 22:00:00 ShengHuo ZHU + + * make-x.bat: New. + +2001-07-04 Yair Friedman + + * make.bat: Use infohack.el to create info files. + +2001-05-17 Kai Gro,A_(Bjohann + + * etc/Makefile.in (datadir): Set this variable, like in the other + Makefile.in's. Patch from Gaute B Strokkenes . + 2001-02-11 18:00:00 ShengHuo ZHU * GNUS-NEWS: Copyright and others. diff --git a/GNUS-NEWS b/GNUS-NEWS index 6334597..4b8d5b5 100644 --- a/GNUS-NEWS +++ b/GNUS-NEWS @@ -8,7 +8,65 @@ For older news, see Gnus info node "New Features". * 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 @@ -16,7 +74,8 @@ variables should change those regexps accordingly. For example: ("^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). diff --git a/Makefile.in b/Makefile.in index 7288565..91bc14c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -17,6 +17,11 @@ install: 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 @@ -41,7 +46,7 @@ xsome: 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 diff --git a/aclocal.m4 b/aclocal.m4 index 1c11603..6307910 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -5,7 +5,7 @@ AC_DEFUN(AM_PATH_LISPDIR, # 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" @@ -177,3 +177,93 @@ fi 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} & 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} & 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} & 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) +]) diff --git a/configure b/configure index dfe4746..3953a6b 100755 --- a/configure +++ b/configure @@ -23,6 +23,8 @@ ac_help="$ac_help --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 @@ -534,7 +536,7 @@ fi 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 @@ -591,7 +593,7 @@ ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. # 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 @@ -663,7 +665,7 @@ fi # 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 @@ -694,7 +696,7 @@ fi # 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 @@ -725,12 +727,12 @@ fi 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 @@ -762,12 +764,12 @@ fi 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 @@ -798,7 +800,7 @@ if test "${with_lispdir+set}" = set; then 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 @@ -824,7 +826,7 @@ if test "${with_etcdir+set}" = set; 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 @@ -833,7 +835,7 @@ echo "configure:828: checking where etc files should go" >&5 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 @@ -841,14 +843,14 @@ 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 @@ -892,7 +894,7 @@ if test "${EMACS_cv_ACCEPTABLE_URL}" = "yes"; then 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 @@ -930,7 +932,7 @@ fi 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 @@ -938,14 +940,14 @@ 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 @@ -989,7 +991,7 @@ if test "${EMACS_cv_ACCEPTABLE_W3}" = "yes"; then 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 @@ -1026,6 +1028,136 @@ fi 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} & 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} & 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} & 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 @@ -1139,7 +1271,7 @@ done 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 <> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then diff --git a/configure.in b/configure.in index 3600414..5368962 100644 --- a/configure.in +++ b/configure.in @@ -22,5 +22,6 @@ AC_PATH_LISPDIR 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) diff --git a/contrib/ChangeLog b/contrib/ChangeLog index a394ef8..2868fdb 100644 --- a/contrib/ChangeLog +++ b/contrib/ChangeLog @@ -1,3 +1,82 @@ +2001-12-26 Florian Weimer + + * gpg.el (gpg-command-default-alist): Using gpg-2comp is no longer + the default. + +2001-12-18 Josh Huber + + * ChangeLog: changed buffer-file-coding-system back to + coding. (oops) + +2001-12-17 Josh Huber + + * ChangeLog: changed coding to buffer-file-coding-system + +2001-11-22 Simon Josefsson + + * sha1.el: Removed. (A FSF copyrighted sha1-el.el file is in + ../lisp/). + +2001-10-30 21:00:00 ShengHuo ZHU + + * canlock.el, hex-util.el, sha1-el.el: Move to lisp. + +2001-10-30 Katsumi Yamaoka + + * 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 + + * canlock.el (canlock-password, canlock-password-for-verify) + (canlock-force-insert-header): Defcustom. + +2001-10-17 Simon Josefsson + + * 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 + + * gpg.el (gpg-command-sign-detached): Doc fix. + +2001-08-07 Andreas Jaeger + + * 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 + From Andreas Fuchs + + * gpg.el (gpg-command-verify): --status-fd 1 + (gpg-unabbrev-trust-alist): New. + 2001-01-18 Colin Marquardt * gpg.el (gpg-make-temp-file): Error info. diff --git a/contrib/gpg-ring.el b/contrib/gpg-ring.el index 31dbfa5..fb22fd9 100644 --- a/contrib/gpg-ring.el +++ b/contrib/gpg-ring.el @@ -7,7 +7,7 @@ ;; 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. @@ -28,11 +28,10 @@ -;;;; Code: +;;; Code: (require 'gpg) -(eval-when-compile - (require 'cl)) +(eval-when-compile (require 'cl)) ;;;; Customization: @@ -481,4 +480,4 @@ used." (provide 'gpg-ring) -;;; gpg-ring.el ends here \ No newline at end of file +;;; gpg-ring.el ends here diff --git a/contrib/gpg.el b/contrib/gpg.el index f5868d5..caf9452 100644 --- a/contrib/gpg.el +++ b/contrib/gpg.el @@ -7,7 +7,7 @@ ;; 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. @@ -41,8 +41,8 @@ ;; * 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 ;; ============================= @@ -106,11 +106,10 @@ ;; function (bound to `C-h l' by default). -;;;; Code: +;;; Code: (require 'timer) -(eval-when-compile - (require 'cl)) +(eval-when-compile (require 'cl)) (eval-and-compile (defalias 'gpg-point-at-eol @@ -228,12 +227,12 @@ If you are running Emacs 20, this directory must have mode 0700." (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) @@ -303,7 +302,7 @@ indicate that it should read the passphrase from standard input." ;;; 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 @@ -324,7 +323,7 @@ charsets or line endings; the input data shall be treated as binary." :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 @@ -365,7 +364,7 @@ standard error." '(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 @@ -378,7 +377,7 @@ standard error." '(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 @@ -632,7 +631,7 @@ adjust according to `gpg-command-passphrase-env'." ;; 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 @@ -764,7 +763,7 @@ Never set this variable directly, use `gpg-show-result' instead.") (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. @@ -802,6 +801,7 @@ evaluates BODY, like `progn'. If BODY evaluates to `nil' (or "Forget stored passphrase." (interactive) (cancel-timer gpg-passphrase-timer) + (setq gpg-passphrase-timer nil) (gpg-passphrase-clear-string gpg-passphrase) (setq gpg-passphrase nil)) @@ -809,6 +809,8 @@ evaluates BODY, like `progn'. If BODY evaluates to `nil' (or "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)) @@ -1176,6 +1178,14 @@ documentation for details)." (?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) diff --git a/contrib/md5.el b/contrib/md5.el index 94d65de..a036819 100644 --- a/contrib/md5.el +++ b/contrib/md5.el @@ -89,7 +89,7 @@ ;; 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 @@ -406,4 +406,4 @@ hash of a portion of OBJECT." (provide 'md5) -;;; md5.el ends here ---------------------------------------------------------- +;;; md5.el ends here diff --git a/contrib/ssl.el b/contrib/ssl.el index a70f0ae..8c93e18 100644 --- a/contrib/ssl.el +++ b/contrib/ssl.el @@ -1,7 +1,7 @@ -;;; 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 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -26,7 +26,7 @@ ;;; Boston, MA 02111-1307, USA. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(require 'cl) +(eval-when-compile (require 'cl)) (require 'base64) (eval-and-compile diff --git a/contrib/vcard.el b/contrib/vcard.el index 334ecd7..a2f298d 100644 --- a/contrib/vcard.el +++ b/contrib/vcard.el @@ -7,7 +7,7 @@ ;; 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 @@ -307,4 +307,4 @@ presentation buffer." (provide 'vcard) -;;; vcard.el ends here. +;;; vcard.el ends here diff --git a/contrib/xml.el b/contrib/xml.el index 25851e2..d128b83 100644 --- a/contrib/xml.el +++ b/contrib/xml.el @@ -1,6 +1,6 @@ -;; @(#) 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 ;; Maintainer: Emmanuel Briot @@ -272,6 +272,8 @@ Returns one of: ;; 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) diff --git a/etc/.cvsignore b/etc/.cvsignore index 7a03f3f..0083161 100644 --- a/etc/.cvsignore +++ b/etc/.cvsignore @@ -1,3 +1,4 @@ +Makefile gnus message smilies diff --git a/etc/Makefile.in b/etc/Makefile.in index efee033..a552a89 100644 --- a/etc/Makefile.in +++ b/etc/Makefile.in @@ -1,3 +1,4 @@ +datadir = @datadir@ infodir = @infodir@ prefix = @prefix@ srcdir = @srcdir@ @@ -34,6 +35,19 @@ install: $(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 diff --git a/lisp/ChangeLog b/lisp/ChangeLog index d1b7ab8..d3071d5 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,3839 @@ +2002-01-01 Lars Magne Ingebrigtsen + + * 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 + + * 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 + + * gnus.el (gnus): Warn if trying to run Gnus un-byte-compiled. + +2001-12-31 Lars Magne Ingebrigtsen + + * 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 + + * imap.el (imap-parse-fetch): Notice empty flags responses. From + Nic Ferrier . + +2001-12-30 ShengHuo ZHU + + * 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 + + * 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 + + * 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 + + * 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 + + * nnrss.el (nnrss-check-group): Find the correct tag, because + xml.el is changed. + +2001-12-30 Lars Magne Ingebrigtsen + + * 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 + + * 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 + + * 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 + + * 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,A|(Bdecke + + * gnus-win.el (gnus-configure-windows): Minimize tree buffer. + +2001-12-29 Lars Magne Ingebrigtsen + + * 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 + + * gnus-sum.el (gnus-summary-limit-to-age): Allow negative days. + +2001-12-29 Lars Magne Ingebrigtsen + + * 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 + + * gnus-art.el (gnus-ignored-headers): Added more headers. + +2001-12-29 Jesper Harder + + * gnus-srvr.el (gnus-browse-foreign-server): Compute the prefix + once. + +2001-12-29 Lars Magne Ingebrigtsen + + * gnus-srvr.el (gnus-server-browse-in-group-buffer): Doc fix. + +2001-12-28 Simon Josefsson + + * gnus-srvr.el (gnus-browse-foreign-server): Fix typo. From + Jesper Harder . + +2001-12-27 Simon Josefsson + + * 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 + + * mm-util.el (mm-iso-8859-x-to-15-region): Use + insert-before-markers. + From Jesper Harder + +2001-12-26 Paul Jarc + + * nnmaildir.el (nnmaildir-save-mail): create the destination + groups if they do not exist. + +2001-12-26 Katsumi Yamaoka + + * canlock.el (canlock-sha1-with-openssl): Remove unused variable. + +2001-12-22 22:00:00 ShengHuo ZHU + + * 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 + + * 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 + + * 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,Bm(Bk + +2001-12-20 15:00:00 ShengHuo ZHU + + * nnmaildir.el: Copyright changes. Require cl only at compile time. + +2001-12-20 Simon Josefsson + + * nnimap.el (top-level): Don't require cl. Suggested by ShengHuo + ZHU . + (nnimap-close-group): Don't quote KEYLIST items. Suggested by + Brian P Templeton . + +2001-12-19 17:00:00 ShengHuo ZHU + + * nnmaildir.el: New. + From Paul Jarc . + +2001-12-19 16:00:00 ShengHuo ZHU + + * nndoc.el (nndoc-type-alist): Move forward to the end. + +2001-12-19 Katsumi Yamaoka + + * gnus.el (gnus-find-subscribed-addresses): Replace `mapc' with + `dolist'. + +2001-12-19 01:00:00 ShengHuo ZHU + + * gnus-win.el (gnus-frames-on-display-list): New. + (gnus-get-buffer-window): Use it. + +2001-12-19 00:00:00 ShengHuo ZHU + + * nnwarchive.el (nnwarchive-mail-archive-xover): Fix the regexp. + +2001-12-18 11:00:00 ShengHuo ZHU + + * gnus-win.el (gnus-get-buffer-window): Use gnus-delete-if. + +2001-12-18 11:00:00 ShengHuo ZHU + From Harald Meland + + * 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 + + * 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 + + * 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 + + * 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 + Inspired by code by Dirk Meyer . + + * 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 + + * 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,Bm(Bk + + * gnus-mlspl.el (gnus-group-split-fancy): Doc fix (add reference + to variable, follow doc-string conventions). + +2001-12-13 Josh Huber + + * 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 + + * gnus-msg.el (gnus-summary-mail-forward): Forward all marked + messages. (A small patch with indentation) + From Sean Neakums . + + * 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 + + * 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 + + * 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 + + * 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 + + * gnus-sum.el (gnus-summary-show-article): Fix doc. + +2001-12-10 17:00:00 ShengHuo ZHU + + * mml.el (mime-to-mml): Remove Content-Disposition too. + +2001-12-09 08:00:00 ShengHuo ZHU + + * gnus-sum.el (gnus-summary-buffer-name): Decode group name. + * gnus-group.el (gnus-group-name-decode): Decode unibyte + strings only. + From TSUCHIYA Masatoshi + +2001-12-08 Nevin Kapur + + * nnmail.el (nnmail-fancy-expiry-targets): New variable. + (nnmail-fancy-expiry-target): Use it. + Suggestions from Simon Josefsson . + +2001-12-07 14:00:00 ShengHuo ZHU + + * gnus-sum.el (gnus-summary-show-article): Recount lines if not exist. + +2001-12-07 10:00:00 ShengHuo ZHU + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * mm-url.el (mm-url-insert-file-contents): Support file:. + +2001-12-05 14:00:00 ShengHuo ZHU + + * mm-view.el: Lower case for the description line. Sync from the + Emacs CVS. + +2001-12-05 12:00:00 ShengHuo ZHU + + * gnus-group.el (gnus-group-find-new-groups): Fix doc. + From: Stefan Monnier + +2001-12-05 Katsumi Yamaoka + + * mm-view.wl (mm-inline-text): Decode a charset-encoded rich text. + +2001-12-04 08:00:00 ShengHuo ZHU + + * mm-url.el: Require executable. + Suggested by Katsumi Yamaoka . + +2001-12-03 11:00:00 ShengHuo ZHU + + * pop3.el (pop3-munge-message-separator): Only use valid date. + From Michael Welsh Duggan . + + * Makefile.in: gnus-load.elc may not be generated. + +2001-12-03 09:00:00 ShengHuo ZHU + + * mm-url.el: New. + * nnslashdot.el: Use it. + * mm-extern.el (mm-extern-url): Use it. + +2001-12-01 15:00:00 ShengHuo ZHU + + * 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 + + * message.el (message-make-mft): Fix the m-s-a-file regexp. + From Paul Jarc . + +2001-11-30 21:00:00 ShengHuo ZHU + + * message.el: New variable message-subscribed-address-file; + use it in message-make-mft. From Paul Jarc . + +2001-11-30 12:00:00 ShengHuo ZHU + + * message.el (message-tab-body-function): Set to nil. + (message-tab): Use text-mode-map or global-map. + Suggested by Kai Gro,A_(Bjohann . + +2001-11-30 Simon Josefsson + + * gnus-agent.el (gnus-agent-fetch-headers): Use gnus-range-add + instead of gnus-union, for speed. Suggested by Christoph Conrad + . + (gnus-agent-fetch-group-1): Add verbose message. + +2001-11-29 12:00:00 ShengHuo ZHU + + * gnus-agent.el (gnus-agent-write-active): Make sure sym is a cons + of integers. + +2001-11-29 Kai Gro,A_(Bjohann + + * 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 + + * gnus-uu.el (gnus-uu-save-article): Use #part instead of #mml. + +2001-11-28 12:00:00 ShengHuo ZHU + + * 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 + + * 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 + + * 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 + + * message.el (message-mode): Use `make-local-hook' unless + obsolete. + Patch by Katsumi Yamaoka . + +2001-11-26 Katsumi Yamaoka + + * canlock.el: Remove sha1.el and base64.el stuff. + +2001-11-26 Didier Verna + + * nnmbox.el (nnmbox-create-mbox): create the mbox file directory + if needed. + +2001-11-21 Katsumi Yamaoka + + * message.el (message-tamago-not-in-use-p): New function. + (message-strip-forbidden-properties): Use it. + +2001-11-26 Didier Verna + + * gnus-start.el (gnus-check-first-time-used): only check for + existence of .el[d] files. + +2001-11-25 15:00:00 ShengHuo ZHU + + * 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 + + * 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,A_(Bjohann + + * message.el (message-wash-subject): Use `insert' rather than + `insert-string', which is deprecated. + +2001-11-24 Simon Josefsson + + * 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 + + * canlock.el (canlock-sha1-with-openssl): Use unibyte + buffer. Correctly decode hex. + +2001-11-21 01:00:00 ShengHuo ZHU + + * gnus-agent.el (gnus-category-insert-line): Convert category + names to strings. + +2001-11-20 21:00:00 ShengHuo ZHU + + * message.el (sha1): eval-and-compile. + +2001-11-20 Simon Josefsson + + * 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 + + * 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 . + +2001-11-20 Didier Verna + + * 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 + + * message.el (message-mode-map): Use C-c C-f C-i for Importance: + instead of C-c C-u. Suggested by Per Abrahamsen + . + +2001-11-18 08:00:00 ShengHuo ZHU + + * nnfolder.el (nnfolder-read-folder): Use group instead of + nnfolder-current-group. + Suggested by Lorentey Karoly . + +2001-11-17 Simon Josefsson + + * 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 + + * 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 + + * 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 + + * message.el (message-strip-special-text-properties): New option. + (message-strip-forbidden-properties): Obey it. + +2001-11-14 Sam Steingold + + * gnus-score.el: Fixed some doc strings to properly quote symbols. + +2001-11-15 Simon Josefsson + + 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 + + * 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 + + * 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 + + * nnml.el (nnml-save-marks): + * nnfolder.el (nnfolder-save-marks): Use `gnus-prin1'. + Suggested by Istvan Marko . + +2001-11-15 Per Abrahamsen + + * gnus-art.el (gnus-article-wash-status-strings): Use + `copy-sequence', not `copy-seq'. + +2001-11-15 Per Abrahamsen + + * 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 + + * mml1991.el: Add coding header. + +2001-11-12 Simon Josefsson + + * 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,A|(Bdecke . + +2001-11-12 13:00:00 ShengHuo ZHU + + * gnus-start.el (gnus-auto-subscribed-groups): Use ^nnml. + + * gnus-sum.el (gnus-summary-move-article): Use number-to-string. + From + +2001-11-11 Simon Josefsson + + * 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 . + +2001-11-09 Simon Josefsson + + * gnus.el (gnus-local-domain): Fix doc. From Pavel Jan,Bm(Bk + . + +2001-11-09 Kai Gro,A_(Bjohann + + * 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 + + * gnus-msg.el (gnus-posting-styles): Add doc. + +2001-11-07 Simon Josefsson + + * 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 + + * 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." . + +2001-11-07 06:00:00 ShengHuo ZHU + + * mml.el (mml-preview): Bind mail-header-separator. + +2001-11-07 Katsumi Yamaoka + + * 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 + + * mail-source.el (mail-source-fetch-imap): ASYNC param. + From: + +2001-11-06 10:00:00 ShengHuo ZHU + + * many files: Fix copyright lines. + +2001-11-05 07:00:00 ShengHuo ZHU + + * mml.el (mml-generate-mime-1): Use mm-with-unibyte-current-buffer. + Suggested by Dave Love . + +2001-11-04 10:00:00 ShengHuo ZHU + + * 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 . + + * gnus-topic.el (gnus-topic-rename): Initial-input. + Suggested by Katsuhiro Hermit Endo . + +2001-11-03 Per Abrahamsen + + * 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 + + * mm-util.el (mm-iso-8859-15-compatible): Fix doc. + (mm-hack-charsets): Fix doc. + +2001-11-02 Simon Josefsson + + * 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 + + * 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 + + * 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 + + * gnus-msg.el (gnus-copy-article-buffer): Copy sequence. + +2001-11-01 12:00:00 ShengHuo ZHU + + * 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 + + * mm-util.el (mm-charset-synonym-alist): Revert (some). + +2001-11-01 09:00:00 ShengHuo ZHU + + * 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 + + * gnus-group.el (gnus-group-make-menu-bar): Add Sieve. + +2001-11-01 08:00:00 ShengHuo ZHU + + * mm-util.el (mm-charset-to-coding-system): Return nil, if charset + is nil. + +2001-11-01 07:00:00 ShengHuo ZHU + + * 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 + + * sieve.el: Don't require easy-mmode. Suggested by Katsumi Yamaoka + . + +2001-10-31 20:00:00 ShengHuo ZHU + + * sieve-manage.el (sieve-string-bytes): No complain. + +2001-11-01 Simon Josefsson + + * 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 + + * 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 + + * gnus.el (gnus-find-subscribed-addresses): Doc fix: + not-subscribed -> subscribed. + +2001-10-31 08:00:00 ShengHuo ZHU + From: Josh Huber + + * 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 + + * 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 + + * 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 : + + * 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 + + * canlock.el, sha1-el.el, hex-util.el: Move from contrib + directory. Thanks to Katsumi Yamaoka and Shuhei + KOBAYASHI . + +2001-10-30 20:00:00 ShengHuo ZHU + + * gnus-art.el (article-display-x-face): Nix buffer-read-only + again. + + * mml2015.el (mml2015-gpg-verify): Convert to . + +2001-10-30 13:00:00 ShengHuo ZHU + + * gnus-spec.el (gnus-parse-simple-format): Use + buffer-substring-no-properties. + +2001-10-30 Katsumi Yamaoka + + * 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 + + * 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 + + * mm-extern.el (mm-extern): Provide it. + + * mm-partial.el (mm-partial): Provide it. + +2001-10-28 16:00:00 ShengHuo ZHU + + * gnus-msg.el (gnus-setup-message): Call post-command-hook. + +2001-10-29 Simon Josefsson + + * mml.el (mml-preview): Bind message-this-is-news if it is + news. From Jesper Harder . + +2001-10-28 Simon Josefsson + + * gnus-sum.el (gnus-group-make-articles-read): Inline group. + +2001-10-29 Per Abrahamsen + + * smiley-ems.el (smiley-regexp-alist): Add support for sad and + ironic smilies. + +2001-10-27 Simon Josefsson + + * message.el (message-indent-citation): Don't add trailing + whitespace when citing text. + + * gnus.el (gnus-group-faq-directory): Fix. From Jesper Harder + . + +2001-10-26 14:00:00 ShengHuo ZHU + + * 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,A_(Bjohann + + * gnus-msg.el (gnus-summary-mail-forward): Doc fix: add pointer to + variable `message-forward-ignored-headers'. + +2001-10-24 Per Abrahamsen + + * 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 + + * 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 + + * gnus.el (post-method): Use `native' instead of `nil'. + + * gnus-msg.el (gnus-post-method): Ditto. + +2001-10-23 Per Abrahamsen + + * gnus.el (gnus-define-group-parameter): Grammar fix. + +2001-10-22 Simon Josefsson + + * gnus-msg.el (gnus-extended-version): Include + system-configuration. + Suggested by Kai.Grossjohann@CS.Uni-Dortmund.DE (Kai Gro,A_(Bjohann). + +2001-10-22 Per Abrahamsen + + * 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 + + * nnimap.el (nnimap): Defgroup + (nnimap-strict-function, nnimap-strict-function-match): New + widget, from Per Abrahamsen . + (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,A_(Bjohann + + * 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 + + * message.el (message-do-auto-fill): Avoid calling + 'rfc822-goto-eoh'. + +2001-10-20 Kai Gro,A_(Bjohann + From Paul Jarc . + + * message.el (message-get-reply-headers): Restructure the logic + and add comments. From Paul Jarc . + +2001-10-20 Simon Josefsson + + * 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 . + + * nnfolder.el (nnfolder-marks-changed-p): Ditto. + +2001-10-19 Per Abrahamsen + + * 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 + + * message.el (message-do-auto-fill): New version that does not + rely on text properties, by Simon Josefsson . + (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 + + * 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 + + * gnus-sum.el (gnus-group-make-articles-read): Call g-r-set-mark + when undoing. + +2001-10-18 Simon Josefsson + From Frank Schmitt + + * gnus-sum.el (gnus-summary-limit-to-display-predicate): Fix typo. + (gnus-summary-make-menu-bar): Ditto. + +2001-10-17 Simon Josefsson + + * nnimap.el (nnimap-expiry-target): Make sure it is back to the + server. Suggested by ShengHuo ZHU . + +2001-10-17 17:00:00 ShengHuo ZHU + + * gnus-sum.el (gnus-summary-line-format-alist): user-date entry. + * gnus-util.el (gnus-user-date): New function. + From Frank Schmitt . + +2001-10-17 Per Abrahamsen + + * 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 + + * 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 + + * 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 + + * gnus-msg.el (gnus-post-method): Changed two instances of + `active' to `current' and one `null' to `not'. + +2001-10-16 Kai Gro,A_(Bjohann + From Katsumi Yamaoka . + + * message.el (message-setup-fill-variables): Use + `normal-auto-fill-function' instead of `auto-fill-function'. + +2001-10-16 Simon Josefsson + + * 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,A_(Bjohann + Patch by Oliver Scholz . + + * 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 + + * 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 + + * 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 + 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 + + * gnus-cache.el (gnus-summary-limit-include-cached): Rewrite. + From Eric Marsden . + +2001-10-12 10:00:00 ShengHuo ZHU + + * message.el (message-do-auto-fill): Use gnus-point-at-bol. + (autoload): Add some autoloads. + +2001-10-12 Kai Gro,A_(Bjohann + Suggested by Oliver Scholz . + + * 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 + + * message.el (message-send-mail-partially): Insert an empty line + first, because of the change of message-make-lines. + +2001-10-10 Florian Weimer + + * 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 + + * 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 + + * 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 + + * dgnushack.el (dgnushack-compile): Detect mh-e and xml. + +2001-10-09 Per Abrahamsen + + * message.el (message-send-news): Oops, missed case with no + "Followup-To" header... + +2001-10-09 Per Abrahamsen + + * 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 + + * Makefile.in (install-el): Depend on gnus-load.el. + +2001-10-07 13:00:00 ShengHuo ZHU + + * Makefile.in (install-el): Use -f. + From: Amos Gouaux + +2001-10-07 Per Abrahamsen + + * 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 + + 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 + + * 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 + + * Makefile.in: Install el in install. Add uninstall. + +2001-10-05 Simon Josefsson + + * 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 + + * mail-source.el (mail-source-movemail-program): New variable. + (mail-source-movemail): Use it. Suggested by Taylor Hutt + . + +2001-10-03 Simon Josefsson + + * gnus-sum.el (gnus-summary-from-or-to-or-newsgroups): New param. + (gnus-summary-line-format-alist): Fix param. + +2001-10-02 Simon Josefsson + + * 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 + + * 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 + + * 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 + + * gnus-sum.el (gnus-summary-extract-address-component): New function. + (gnus-summary-from-or-to-or-newsgroups): Optimize. + +2001-09-29 Kai Gro,A_(Bjohann + + * 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 + + * 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 + + * gnus-xmas.el (gnus-article-x-face-command): Merge it into + gnus-art.el. + +2001-09-27 Simon Josefsson + + * gnus-topic.el (gnus-topic-mode-map): Add catchup. + (gnus-topic-catchup-articles): New function. Suggested by Robin + S. Socha . + +2001-09-27 11:00:00 ShengHuo ZHU + From Gerd M,Av(Bllmann . + + * gnus-ems.el (gnus-article-display-xface): Insert xface after + previous ones. + +2001-09-27 07:00:00 ShengHuo ZHU + From Daiki Ueno + + * gnus-sum.el (gnus-summary-show-article): The arglist of + detect-coding-region is incompatible. + +2001-09-26 18:00:00 ShengHuo ZHU + From Katsuhiro Hermit Endo + + * gnus-group.el (gnus-group-delete-group): Typo. + +2001-09-26 Simon Josefsson + + * 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 + + * gnus-cus.el (gnus-group-parameters): Display as sexp. + +2001-09-22 Simon Josefsson + + * 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 + + * gnus-sum.el (gnus-summary-mode-hook): Add gnus-pick-mode as + custom option. + +2001-09-23 Simon Josefsson + + * gnus-draft.el (gnus-draft-setup): Add mark in backend as well. + +2001-09-23 02:00:00 ShengHuo ZHU + + * gnus-msg.el (gnus-button-mailto): Hack save-selected-window-window. + +2001-09-22 Per Abrahamsen + + * gnus-group.el (gnus-group-sort-function): Fix customize type to + accept lists of functions. + +2001-09-20 Simon Josefsson + + * 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,A_(Bjohann + + * message.el (message-tab-body-function): New variable. + * message.el (message-tab): Use it. + +2001-09-19 Sam Steingold + + * gnus-win.el (gnus-buffer-configuration): Respect + `gnus-bug-create-help-buffer'. + +2001-09-18 Simon Josefsson + + * gnus-spec.el (gnus-correct-pad-form): Re-revert. + (gnus-parse-simple-format): Re-revert. + +2001-09-16 Katsuhiro Hermit Endo + + * gnus-spec.el (gnus-parse-complex-format): Don't fold search + case. (Thanks to Daiki Ueno .) + +2001-09-18 Simon Josefsson + + * 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 + + * 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 + + * gnus-srvr.el (gnus-server-mode): Fix bogus fontification. + From Gerd M,Av(Bllmann . + +2001-09-17 Didier Verna + + * 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 + + * 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 + + * gnus-spec.el (gnus-parse-format): Don't treat %c as %C. + +2001-09-13 Martin Kretzschmar + + * 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 + + * 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,Bm(Bk + + * 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 + + * 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 + + * 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 + + * 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 + From Daniel Pittman + + * gnus-spec.el (gnus-correct-pad-form): Fix. + +2001-09-09 Simon Josefsson + + * 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 + + * 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 + + * 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 + From Daniel Pittman + + * gnus-spec.el (gnus-correct-pad-form): New function. + (gnus-parse-simple-format): Use it. + +2001-09-07 Simon Josefsson + + * gnus-group.el (gnus-group-sort-groups): Unmark all groups. + (gnus-group-sort-selected-groups): Ditto. Suggested by Harry + Putnam . + (gnus-group-sort-selected-groups): Touch dribble file. + +2001-09-07 Raja R Harinath + + * 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 + + * gnus-sum.el (gnus-summary-insert-line): Fix. + +2001-09-06 Bj,Av(Brn Torkelsson + + * 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 + + * gnus-start.el (gnus-setup-news): A typo. + From Bill White . + +2001-09-06 Simon Josefsson + + * gnus-sum.el (gnus-summary-insert-line): Insert forwarded, recent + and unseen marks. + +2001-09-05 Kai Gro,A_(Bjohann + + * nnmail.el (nnmail-split-fancy): Document `junk'. + +2001-09-04 Simon Josefsson + + * imap.el (imap-search): Don't error if server is broken. + +2001-09-02 Benjamin Rutt + + * 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 + + * nnslashdot.el (nnslashdot-retrieve-headers-1): Get references + right, and get all the comments. + +2001-09-02 Simon Josefsson + Suggested by Dan Christensen + + * nnfolder.el (nnfolder-request-update-info): Fix message. + + * nnml.el (nnml-request-update-info): Ditto. + +2001-09-01 Simon Josefsson + + * 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 + + * imap.el (imap-mailbox-examine, imap-mailbox-examine-1): Fix a + typo: `exmine' --> `examine'. + +2001-08-30 13:00:00 ShengHuo ZHU + + * nndoc.el (nndoc-forward-type-p): It is not a digest. + +2001-08-30 11:00:00 ShengHuo ZHU + + * 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 + + * 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 + + * 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 + + * mm-decode.el (mm-display-external): Use `name' as filename, if + `filename' attribute is not present. + +2001-08-30 Andrew Innes + + * 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 + + * gnus-sum.el (gnus-summary-move-article): Only update marks of + type 'list. + +2001-08-29 00:00:00 ShengHuo ZHU + + * flow-fill.el (fill-flowed): eol might be point-max. + +2001-08-27 Simon Josefsson + + * 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 + + * nnfolder.el (nnfolder-save-marks): Don't create directory named + after group in ~/. + +2001-08-25 Simon Josefsson + From Andreas Jaeger + + * nnfolder.el (nnfolder-open-marks): Fix typo. + * nnml.el (nnml-open-marks): Likewise. + +2001-08-25 Simon Josefsson + + 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 + + * 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 + + * nnml.el (nnml-marks-is-evil): Add doc. + +2001-08-25 Simon Josefsson + + * 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 + + * 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 + + * mml.el (mml-generate-mime-1): Force as multibyte string. + +2001-08-24 12:00:00 ShengHuo ZHU + + * gnus-sum.el (gnus-summary-insert-line) + (gnus-summary-prepare-threads): gnus-tmp-lines should be a string. + From Martin Kretzschmar + + * 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 + + * 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 + + * gnus-util.el (gnus-create-info-command): Return an interactive + function. + +2001-08-23 19:00:00 ShengHuo ZHU + From Katsumi Yamaoka + + * gnus-spec.el (gnus-parse-complex-format): Use equal. + +2001-08-23 18:43:05 Lars Magne Ingebrigtsen + + * 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 + + * 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 + + * 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 + + * gnus.el (gnus-visual-p): Define function before use of + function. + +2001-08-21 23:28:02 Lars Magne Ingebrigtsen + + * 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 + + * 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 + + * gnus-start.el (gnus-activate-group): If dont-check, don't update + active. + +2001-08-20 15:00:00 ShengHuo ZHU + + * 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 + + * 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 + + * 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 + + * 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,Bm(Bk + + * earcon.el (earcon-auto-play): Remove unused option. + +2001-08-19 16:14:41 Lars Magne Ingebrigtsen + + * 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 + + * 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 + From Joe Casadonte + + * 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 + + * 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 + + * 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 + + * 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 + + * nnslashdot.el (nnslashdot-threaded-retrieve-headers): + slashdot 2.2 (not fully fixed yet). + (nnslashdot-request-article): Ditto. + +2001-08-18 Simon Josefsson + + * 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 + + 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 + + * gnus-sum.el (gnus-summary-move-article): Use `add' instead of + `set' when setting marks. + +2001-08-17 22:00:00 ShengHuo ZHU + + * 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 + + * message.el (message-check-news-header-syntax): Check bad From. + +2001-08-18 00:14:45 Lars Magne Ingebrigtsen + + * gnus-spec.el (gnus-correct-length): New function. + (gnus-correct-substring): New function. + (gnus-tilde-max-form): Use it. + +2001-08-17 Nevin Kapur + + * 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 + + * mml.el (mml-menu): Collapse Attach, Insert and Security submenu. + +2001-08-17 Bj,Av(Brn Torkelsson + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * gnus-srvr.el (gnus-server-browse-in-group-buffer): Default to + nil. + +2001-08-15 Kai Gro,A_(Bjohann + + * gnus-delay.el (gnus-delay-article): Allow "01:23" time spec, + which specifies a time today or tomorrow. + +2001-08-15 Simon Josefsson + From Pavel@Janik.cz (Pavel Jan,Bm(Bk) + + * gnus-agent.el (gnus-agent-make-mode-line-string) + (gnus-agent-toggle-plugged): Use new API. + +2001-08-14 Kai Gro,A_(Bjohann + + * gnus-delay.el (gnus-delay-send-drafts): Fix check whether + deadline has expired. + +2001-08-12 Simon Josefsson + 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 + + * mm-bodies.el (mm-decode-content-transfer-encoding): Returns + whether successful decoding took place. Add doc. + +2001-08-12 Simon Josefsson + Suggested by Per Abrahamsen + + * 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 + Committed by Kai Gro,A_(Bjohann. + + * gnus-score.el (gnus-score-string): Fix `match' regexp + for `extra' header case. + +2001-08-10 23:00:00 ShengHuo ZHU + + * nnmbox.el (nnmbox-read-mbox): No warning. + +2001-08-10 21:00:00 ShengHuo ZHU + + * 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,A_(Bjohann + + * gnus-delay.el (gnus-delay-send-drafts): Cleaner way to check + whether deadline has been reached. Patch from Dan Nicolaescu + . + +2001-08-10 02:00:00 ShengHuo ZHU + + * gnus-ml.el (turn-on-gnus-mailing-list-mode): Use + gnus-group-find-parameter. Suggested by Janne Rinta-Manty + . + + * mail-source.el (mail-source-movemail): The error buffer is + modified, but nothing in it. + +2001-08-10 01:00:00 ShengHuo ZHU + + * message.el (message-bogus-system-names): New. + (message-make-fqdn): Use it. + +2001-08-09 15:00:00 ShengHuo ZHU + + * nndraft.el (nndraft-request-group): Use + nndraft-auto-save-file-name. + +2001-08-09 Simon Josefsson + + * 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 + + * 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 + + * message.el (message-tab): Use indent-relative. + (message-mode): Don't bind indent-line-function to indent-relative. + +2001-08-09 Simon Josefsson + + * message.el (message-get-reply-headers): Fix string. Suggested by + Christoph Conrad . + +2001-08-08 15:00:00 ShengHuo ZHU + + * 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 + + * imap.el (imap-gssapi-auth-p, imap-kerberos4-auth-p): Also check + whether `imtest' is installed. + +2001-08-04 Nuutti Kotivuori + Committed by ShengHuo ZHU + + * 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 + + * 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,Av(Bllmann + . + + * 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 + + * message.el (message-indent-citation): Use + `message-yank-cited-prefix' for empty lines. + +2001-08-05 Florian Weimer + + * message.el (message-indent-citation): Quote only lines starting + with ">" using `message-yank-cited-prefix'. + +2001-08-05 Nuutti Kotivuori + + * gnus-cache.el (gnus-cache-possibly-enter-article): Use + gnus-cache-fully-p. + +2001-08-04 Simon Josefsson + + * 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 + + * 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 + + * 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 . + +2001-08-04 Nuutti Kotivuori + Committed by Simon Josefsson + + * 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 + + * gnus-art.el (gnus-mime-security-verify-or-decrypt): Insert + before remove. + (gnus-mime-security-show-details): Ditto. + +2001-08-04 Kai Gro,A_(Bjohann + + * 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 + + * mm-util.el (mm-find-charset-region): Remove control-1. + +2001-08-03 17:00:00 ShengHuo ZHU + + * mm-decode.el (mm-readable-p): Emacs 20 takes one argument. + +2001-08-04 Simon Josefsson + + * smime.el (smime-sign-region, smime-encrypt-region): Fix details + buffer. Delete MIME-Version header. + +2001-08-03 Simon Josefsson + + * 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 + + * mml2015.el (mml2015-gpg-extract-signature-details): Don't barf. + +2001-08-03 Simon Josefsson + + * mml.el (mml-menu): Rename from MML to Mime. Collapse Security + menu. + +2001-08-02 Katsumi Yamaoka + + * 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 + + * smime.el (smime-extra-arguments): Removed. + (smime-call-openssl-region): Don't use it. + +2001-08-02 Simon Josefsson + + * 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 + From Andreas Fuchs + + * mml2015.el (mml2015-trust-boundaries-alist): Typo. + +2001-08-01 10:00:00 ShengHuo ZHU + + * gnus-art.el (gnus-header-button-alist): References regexp. + +2001-08-01 Gerd Moellmann + + * 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 + + * nnslashdot.el (nnslashdot-init): Add as gnus buffer. + + * nnmail.el (nnmail-cache-open): Ditto. + +2001-07-31 21:00:00 ShengHuo ZHU + + * gnus-art.el (gnus-button-fetch-group): Fix the regexp. + +2001-07-31 Katsumi Yamaoka + + * gnus-msg.el (gnus-post-method): Refer to `gnus-parameters'. + +2001-07-31 17:00:00 ShengHuo ZHU + Originally from Pavel Jan,Bm(Bk + + * gnus-agent.el (gnus-agent-make-mode-line-string): New. + (gnus-agent-toggle-plugged): Use it. + +2001-07-31 ShengHuo ZHU + + * 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,A_(Bjohann + + * gnus-delay.el (gnus-delay-initialize): Use standard define-key + syntax. + +2001-07-30 15:00:00 ShengHuo ZHU + Originally from Andreas Fuchs + + * 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 + + * mml-smime.el (mml-smime-sign, mml-smime-encrypt): Goto end of + buffer when done. + +2001-07-30 Simon Josefsson + + * 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 + + * gnus-art.el (gnus-mime-save-part-and-strip): Save + gnus-article-mime-handles. + +2001-07-29 Simon Josefsson + + * 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 + From Vladimir Volovich + + * smime.el (smime-call-openssl-region): Ignore stderr. + +2001-07-29 Simon Josefsson + From Christoph Conrad + + * gnus-agent.el (gnus-agent-save-group-info): Don't destroy active + file. + +2001-07-29 Simon Josefsson + + * 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 + + * 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 + . + +2001-07-29 Kai Gro,A_(Bjohann + + * 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 + + * message.el (message-fill-paragraph): Do nothing if the user + wants filladapt-mode. + +2001-07-27 23:00:00 ShengHuo ZHU + + * mm-decode.el (mm-image-type-from-buffer): New. + (mm-get-image): Use it. + +2001-07-27 18:00:00 ShengHuo ZHU + + * 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 + + * 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 + + * 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 + + * 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 + + * nnfolder.el (nnfolder-request-accept-article): Replace + nnfolder-request-list. + +2001-07-27 Simon Josefsson + + * 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 + + * gnus.el (gnus-parameters): Make it customizable. + +2001-07-26 15:00:00 ShengHuo ZHU + + * 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 + + * mm-decode.el (mm-readable-p): New. + (mm-inline-media-tests): Fix the default testers. + +2001-07-26 Simon Josefsson + + * nnimap.el (nnimap-version): Bump version number. + +2001-07-26 10:00:00 ShengHuo ZHU + From Steven E. Harris + + * nnheader.el (nnheader-translate-file-chars): cygwin32 is running + in M$Windows too. + +2001-07-26 Kai Gro,A_(Bjohann + + * gnus-delay.el (gnus-delay-send-drafts): Don't `error'. + +2001-07-25 21:00:00 ShengHuo ZHU + + * 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 + + * 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 + From Henrik Enberg + + * gnus-msg.el: Customization patch. + +2001-07-25 22:22:22 Raymond Scholz + + * 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 + + * 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 + + * message.el (message-use-mail-followup-to): `t' is not a + documented value. + +2001-07-24 13:00:00 ShengHuo ZHU + + * gnus-sum.el (gnus-summary-display-arrow): Test fboundp. + +2001-07-24 12:00:00 ShengHuo ZHU + + * mm-encode.el (mm-encode-buffer): Don't use 7bit encoding if + there are long lines. + +2001-07-24 Katsumi Yamaoka + + * dgnushack.el (copy-list): New compiler macro. + +2001-07-24 09:00:00 ShengHuo ZHU + + * 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 + + * 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,A_(Bjohann + + * 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 + From Karl Kleinpaste + + * 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 + + * 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 + + * 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 + + * gnus-start.el (gnus-setup-news): Call + `gnus-check-bogus-newsgroups' just after the native server is + opened. + +2001-07-23 Kai Gro,A_(Bjohann + + * 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 + + * gnus-msg.el (gnus-setup-message): make-local-hook. + +2001-07-22 Kai Gro,A_(Bjohann + + * gnus-delay.el (gnus-delay-article): Fix `read-string' for + XEmacs. Allow more units. Submitted by Karl Kleinpaste + , 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,A_(Bjohann + + * gnus-delay.el: New file. + +2001-07-21 13:00:00 ShengHuo ZHU + + * 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,A_(Bjohann + + * nnml.el (nnml-request-post): New function. Can be used for + annotations in nnml groups. + +2001-07-19 Katsumi Yamaoka + + * 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 + + * gnus-score.el (gnus-home-score-file): nnheader-translate-file-chars. + +2001-07-18 Per Abrahamsen + + * message.el (message-shorten-references): Change `maxcount' and + `cut' to obey USEFOR draft 5. + +2001-07-12 Colin Walters + + * 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 + + * gnus-sum.el (gnus-summary-import-article): Insert date if + doesn't exist. + +2001-07-18 11:00:00 ShengHuo ZHU + + * 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 + + * 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 + + * dgnushack.el (dgnushack-make-auto-load): Advise `make-autoload' + to handle `define-derived-mode'. + +2001-07-16 12:00:00 ShengHuo ZHU + From: Stefan Monnier + + * 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,A_(Bjohann + + * message.el (message-citation-line-function): Refer to + gnus-cite-attribution-suffix. + +2001-07-15 Pavel Jan,Bm(Bk + + * gnus-art.el,...: Error convention changes. + +2001-07-13 20:00:00 ShengHuo ZHU + + * gnus-sum.el (gnus-rebuild-thread): Count hidden lines too. + +2001-07-13 20:00:00 ShengHuo ZHU + + * nnrss.el (nnrss-read-group-data): Nuke emacs-lisp-mode-hook. + (nnrss-read-server-data): Ditto. + +2001-07-13 12:00:00 ShengHuo ZHU + + * gnus-setup.el (gnus-use-installed-gnus): Typo. + * Cleanup files. + From Pavel@Janik.cz (Pavel Jan,Bm(Bk). + +2001-07-13 08:00:00 ShengHuo ZHU + + * 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 + + * gnus-art.el (gnus-boring-article-headers): Better doc. + (article-hide-headers): Better regexp. + Suggested by Matt Swift . + + * nnheader.el (nnheader-max-head-length): Better doc. + (nnheader-header-value): Skip spaces. + (nnheader-parse-head): Remove space. + Suggested by Matt Swift . + + * gnus-sum.el (gnus-summary-show-raw-article): New function. + (gnus-get-newsgroup-headers): Remove space. + +2001-07-12 23:00:00 ShengHuo ZHU + + * 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 + + * gnus-draft.el (gnus-draft-setup): Restore gnus-newsgroup-name. + +2001-07-12 15:00:00 ShengHuo ZHU + + * 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,Av(Brn Torkelsson + + * 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 + + * gnus-msg.el (gnus-inews-do-gcc): Don't test gnus-alive-p. + +2001-07-11 18:00:00 ShengHuo ZHU + + * 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 + + * 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,Bm(Bk + + * gnus-logic.el, gnus-srvr.el, gnus-vm.el, nnheaderxm.el, nnoo.el: + Cleanup. + +2001-07-09 23:00:00 ShengHuo ZHU + + * 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 + + * mm-decode.el (mm-attachment-override-p): Fix typo. + +2001-03-19 05:28:00 Katsumi Yamaoka + + * 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 + + * mm-view.el (mm-inline-text): w3-coding-system-for-mime-charset + may not defined. From: Raja R Harinath . + + * 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 + + * 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 + + * 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 + From Paul Jarc + + * message.el (message-use-mail-followup-to): New variable. + (message-get-reply-headers): Use it. + +2001-07-04 Gerd Moellmann + + * 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 + + * gnus-sum.el (gnus-get-newsgroup-headers-xover): Get headers only + when it returns headers. + +2001-07-07 Simon Josefsson + + * rfc2047.el (rfc2047-encode-message-header): Skip header when + trying to fold. Thanks to Colin Walters + + +2001-07-06 Simon Josefsson + + * 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 + + * rfc2047.el (rfc2047-encode-message-header): Don't include the + header name when folding. + +2001-07-05 Colin Walters + + * 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 + + * nnimap.el (nnimap-importantize-dormant): New variable. + (nnimap-request-update-info-internal): Use it. + (nnimap-request-set-mark): Ditto. + +2001-07-04 Didier Verna + + * 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 + + * 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 + + * gnus-start.el (gnus-check-first-time-used): Use `if' instead of + `when'. + +2001-07-03 Simon Josefsson + From Nuutti Kotivuori + + * flow-fill.el (fill-flowed): Use (1+ (point-at-eol)) instead. + +2001-07-03 Simon Josefsson + + * flow-fill.el (fill-flowed): If `fill-region' inserts empty line, + remove it (workaround XEmacs `fill-region' bug). + +2001-07-01 Simon Josefsson + + * nnimap.el (nnimap-date-days-ago): Defeat locale. + +2001-06-28 11:00:00 ShengHuo ZHU + + * 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 + + * nnrss.el (nnrss-retrieve-headers): The description may not exist. + Suggested by Christoph Conrad . + + * gnus-sum.el (gnus-summary-set-local-parameters): Don't override + group variables. + +2001-06-25 10:00:00 ShengHuo ZHU + + * 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 + + * message.el (message-do-send-housekeeping): Narrow to headers. + +2001-06-24 Simon Josefsson + + * 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 + From Samuel Tardieu + + * 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 + + * smime.el (smime-decrypt-region): Perhaps work. + +2001-06-22 10:00:00 ShengHuo ZHU + + * gnus-msg.el (gnus-copy-article-buffer): Typo. + +2001-04-06 Ralph Schleicher + + * 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 + + * message.el (message-make-date): Workaround locale for weekdays. + +2001-06-21 17:00:00 ShengHuo ZHU + + * message.el (message-goto-body): Return nil if not found. (revert!) + +2001-06-21 10:00:00 ShengHuo ZHU + From Fremlin + + * message.el (message-goto-body): Some messages have no header. + + * gnus-msg.el (gnus-copy-article-buffer): Use it. + +2001-06-21 Ralph Schleicher + + * nnultimate.el (nnultimate-retrieve-headers): Date fix. + +2001-06-21 10:00:00 ShengHuo ZHU + + * message.el (message-make-date): Add week day. + Suggested by Jason R. Mastaler . + +2001-06-19 Simon Josefsson + + * 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 + + * 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 + for his work. + +2000-12-30 NAGY Andras + + * imap.el (imap-ssl-program): Add -quiet to shut up + OpenSSL/SSLeay's internal debug talk. + +2001-06-19 Matt Armstrong + + * imap.el (imap-parse-flag-list): Workaround bug in Courier IMAP + server. + +2001-06-19 10:00:00 ShengHuo ZHU + + * nnmail.el (nnmail-article-buffer): New variable. + (nnmail-split-incoming): Use it. + +2001-06-15 Eli Zaretskii + + * qp.el (quoted-printable-decode-region): If called interactively, + use coding-system-for-read. + +2001-06-16 09:00:00 ShengHuo ZHU + + * message.el (message-check-news-header-syntax): Check Reply-To. + +2001-06-16 08:00:00 ShengHuo ZHU + + * 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 + + * 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 + + * message.el (message-send-mail-with-qmail): wrong exit status is + 100 not 1. Reported by Paul Jarc . + +2001-06-15 09:00:00 ShengHuo ZHU + + * gnus-art.el (article-strip-multiple-blank-lines): Use + delete-region instead of replace-match. + +2001-06-14 16:00:00 ShengHuo ZHU + + * nnweb.el (nnweb-google-parse-1): Fix Google content regexp. + (nnweb-google-wash-article): Ditto. + +2001-06-14 Ferenc Wagner + + * nnweb.el (nnweb-google-parse-1): Fix Google url regexp. + +2001-06-13 Katsumi Yamaoka + + * gnus.el (gnus-define-group-parameter): Don't quote the defcustom + specs. + +2001-06-13 15:00:00 ShengHuo ZHU + + * 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 + + * message.el (message-options-set-recipient): Don't add ", " + unless necessary. Suggested by Josh Huber . + +2001-06-12 12:00:00 ShengHuo ZHU + + * nnrss.el (nnrss-group-alist): Use |fr| instead of [fr]. + +2001-06-12 11:00:00 ShengHuo ZHU + + * gnus-art.el (gnus-plain-save-name): Use file-relative-name. + From Marc Lefranc . + + * nnrss.el (nnrss-node-text): Node might be nil. + +2001-06-11 10:00:00 ShengHuo ZHU + + * gnus-uu.el (gnus-uu-save-article): Use mml tag instead of + part. From Katsumi Yamaoka . + + * nnrss.el (nnrss-group-alist): More items. + +2001-06-09 23:00:00 ShengHuo ZHU + + * nnrss.el (nnrss-node-text): Use cddr instead xml-node-children. + +2001-06-03 Dale Hagglund + + * gnus-mlspl.el (gnus-group-split-fancy): Fix generation of split + restrict clauses. + +2001-06-07 16:00:00 ShengHuo ZHU + + From Benjamin Rutt + + * message.el (message-wide-reply-confirm-recipients): New variable. + +2001-06-06 Mark Thomas + + * 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 + + * nnrss.el (nnrss-retrieve-headers): Support description as extra + headers. + +2001-06-07 15:00:00 ShengHuo ZHU + + * nnrss.el: Fix a few bugs. + +2001-06-05 Simon Josefsson + + * mm-decode.el (mm-handle-set-external-undisplayer): Don't + generate compiler warnings. From Alex Schroeder . + +2001-06-04 Hrvoje Niksic + + * 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 + + * 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 + + * 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 + for report and partial patch and Jake + Colman for report. + +2001-05-31 13:00:00 ShengHuo ZHU + + * gnus-sum.el (gnus-summary-catchup): New argument. + (gnus-summary-catchup-from-here): New function. + +2001-05-30 Kai Gro,A_(Bjohann + + * 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 . + +2001-05-28 Kai Gro,A_(Bjohann + + 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,A_(Bjohann + + * gnus-salt.el (gnus-tree-highlight-node): Bind `default-high' and + `default-low' when evaluating `gnus-summary-highlight'. + From Raja R Harinath . + +2001-05-27 Simon Josefsson + + * 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,A_(Bjohann + From Nevin Kapur . + + * 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 + + * message.el (message-mail): pass the 'send-actions argument to + `message-setup'. + +2001-05-16 Simon Josefsson + From Raymond Scholz + + * gnus-art.el (gnus-mime-view-part-as-charset): + (gnus-mime-internalize-part): Doc fixes. + +2001-05-11 Simon Josefsson + + * gnus-start.el (gnus-ignored-newsgroups): Also ignore NNTP type + status lines without any text ("^215$"). + +2001-05-06 21:00:00 ShengHuo ZHU + + * nnrss.el (nnrss-check-group): Reverse. + +2001-05-07 Simon Josefsson + + * message.el (message-get-reply-headers): + (message-followup): Fix typo, suggested by David Green + + +2001-05-05 15:00:00 ShengHuo ZHU + + * 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 + + * message.el (message-do-send-housekeeping): mail-abbrevs may + rename buffer behind Gnus. + +2001-05-04 14:00:00 ShengHuo ZHU + + * 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 + + * 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 + + * message.el (message-use-followup-to): Set default value to t. + +2001-05-03 Florian Weimer + + * 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 + + * nnrss.el (nnrss-request-expire-articles): Calculate # of days + correctly. + (nnrss-check-group): Use time. + 2001-05-01 19:21:19 Lars Magne Ingebrigtsen * gnus.el: Oort Gnus v0.03 is released. @@ -14,7 +3850,7 @@ 2001-04-15 14:55:03 Lars Magne Ingebrigtsen * 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. @@ -43,7 +3879,7 @@ 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] . 2001-04-25 Per Abrahamsen @@ -94,7 +3930,7 @@ * 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. @@ -113,7 +3949,7 @@ * 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 * message.el (message-cite-prefix-regexp): Use POSIX regexp if @@ -146,12 +3982,12 @@ 2001-04-05 21:43:25 Lars Magne Ingebrigtsen * gnus-sum.el (gnus-update-summary-mark-positions): Use a valid - date. + date. 2001-04-04 16:13:17 Lars Magne Ingebrigtsen * gnus-group.el (gnus-group-quit): Check that the dribble buffer - lives. + lives. 2001-04-02 00:40:12 Lars Magne Ingebrigtsen @@ -162,7 +3998,7 @@ * 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. @@ -177,13 +4013,13 @@ * 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. @@ -200,7 +4036,7 @@ `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 * gnus-start.el (gnus-close-all-servers): New function. @@ -209,7 +4045,7 @@ (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 @@ -223,9 +4059,9 @@ * 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. @@ -244,7 +4080,7 @@ 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 @@ -261,14 +4097,14 @@ * 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. @@ -284,7 +4120,7 @@ (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. @@ -292,7 +4128,7 @@ 2001-03-21 20:00:43 Lars Magne Ingebrigtsen * nnultimate.el (nnultimate-retrieve-headers): Work for other - boards. + boards. 2001-03-21 Didier Verna @@ -349,7 +4185,7 @@ 2001-03-10 Matthias Wiehl - * gnus.el (gnus-summary-line-format): Typo. + * gnus.el (gnus-summary-line-format): Typo. 2001-03-11 Simon Josefsson @@ -633,7 +4469,7 @@ (nnml-request-regenerate): Use it. Change to deffoo. 2001-02-14 Katsumi Yamaoka - Committed by ShengHuo ZHU + Committed by ShengHuo ZHU * gnus.el (gnus-define-group-parameter): Fix. @@ -1034,7 +4870,7 @@ 2001-01-19 Simon Josefsson - * 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 diff --git a/lisp/Makefile.in b/lisp/Makefile.in index cb91295..374a730 100644 --- a/lisp/Makefile.in +++ b/lisp/Makefile.in @@ -15,36 +15,51 @@ W3DIR = @W3@ 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 @@ -54,7 +69,7 @@ separately: 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 diff --git a/lisp/binhex.el b/lisp/binhex.el index 0147921..120821f 100644 --- a/lisp/binhex.el +++ b/lisp/binhex.el @@ -1,5 +1,5 @@ -;;; 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 ;; Keywords: binhex news @@ -25,6 +25,8 @@ ;;; Code: +(autoload 'executable-find "executable") + (eval-when-compile (require 'cl)) (eval-and-compile @@ -33,13 +35,23 @@ '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) @@ -184,8 +196,9 @@ input and write the converted data to its standard output.") (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) @@ -258,12 +271,14 @@ If HEADER-ONLY is non-nil only decode header and return filename." (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) @@ -296,6 +311,14 @@ If HEADER-ONLY is non-nil only decode header and return filename." (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 diff --git a/lisp/canlock.el b/lisp/canlock.el new file mode 100644 index 0000000..9b8dfb6 --- /dev/null +++ b/lisp/canlock.el @@ -0,0 +1,319 @@ +;;; canlock.el --- functions for Cancel-Lock feature +;; Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc. + +;; Author: Katsumi Yamaoka +;; 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 diff --git a/lisp/dgnushack.el b/lisp/dgnushack.el index 29d822a..d37f23c 100644 --- a/lisp/dgnushack.el +++ b/lisp/dgnushack.el @@ -46,7 +46,7 @@ (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) @@ -157,6 +157,17 @@ (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 @@ -221,18 +232,25 @@ Modify to suit your needs.")) (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) @@ -266,10 +284,24 @@ Modify to suit your needs.")) (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 @@ -322,7 +354,19 @@ Modify to suit your needs.")) ;;; 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)) diff --git a/lisp/dig.el b/lisp/dig.el index 18019e9..d719c38 100644 --- a/lisp/dig.el +++ b/lisp/dig.el @@ -1,5 +1,5 @@ ;;; 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 ;; Keywords: DNS BIND dig @@ -31,6 +31,10 @@ ;; 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)) @@ -58,9 +62,9 @@ If nil, use system defaults." "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 @@ -89,7 +93,7 @@ Buffer should contain output generated by `dig-invoke'." (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) @@ -144,7 +148,7 @@ Buffer should contain output generated by `dig-invoke'." '(dig-font-lock-keywords t))) (when (featurep 'font-lock) (font-lock-set-defaults))) - + (defun dig-exit () "Quit dig output buffer." (interactive) @@ -155,7 +159,7 @@ Buffer should contain output generated by `dig-invoke'." "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) diff --git a/lisp/earcon.el b/lisp/earcon.el index 7c42e8b..faa38c5 100644 --- a/lisp/earcon.el +++ b/lisp/earcon.el @@ -1,6 +1,6 @@ ;;; 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 @@ -35,11 +35,6 @@ "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 @@ -83,7 +78,7 @@ call it with the value of the `earcon-data' text property." (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)))) diff --git a/lisp/flow-fill.el b/lisp/flow-fill.el index 64946f9..de3dd4b 100644 --- a/lisp/flow-fill.el +++ b/lisp/flow-fill.el @@ -1,6 +1,6 @@ ;;; 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 ;; Keywords: mail @@ -38,7 +38,7 @@ ;; 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 @@ -95,7 +95,7 @@ (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) diff --git a/lisp/gnus-agent.el b/lisp/gnus-agent.el index d5c9017..6595802 100644 --- a/lisp/gnus-agent.el +++ b/lisp/gnus-agent.el @@ -1,5 +1,5 @@ ;;; 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 @@ -260,7 +260,7 @@ If this is `ask' the hook will query the user." "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) @@ -271,7 +271,7 @@ If this is `ask' the hook will query the user." '("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]))))) @@ -279,6 +279,7 @@ If this is `ask' the hook will query the user." (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 @@ -293,6 +294,7 @@ If this is `ask' the hook will query the user." ["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)) @@ -310,6 +312,13 @@ If this is `ask' the hook will query the user." ["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))) @@ -318,11 +327,17 @@ If this is `ask' the hook will query the user." (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 () @@ -354,14 +369,16 @@ last form in your `.gnus.el' file: \(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)))) @@ -416,8 +433,7 @@ be a 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))) @@ -449,14 +465,20 @@ be a select method." (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." @@ -543,7 +565,7 @@ be a select method." (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) @@ -556,7 +578,7 @@ be a select method." (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)) @@ -663,6 +685,29 @@ the actual number of articles toggled is returned." (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 ;;; @@ -693,7 +738,12 @@ the actual number of articles toggled is returned." (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)) @@ -711,7 +761,7 @@ the actual number of articles toggled is returned." (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. @@ -721,17 +771,13 @@ the actual number of articles toggled is returned." (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)))))) @@ -956,9 +1002,8 @@ the actual number of articles toggled is returned." (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 @@ -1048,7 +1093,8 @@ the actual number of articles toggled is returned." (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)) @@ -1103,12 +1149,12 @@ the actual number of articles toggled is returned." (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")))) @@ -1129,7 +1175,8 @@ the actual number of articles toggled is returned." (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. @@ -1146,10 +1193,9 @@ the actual number of articles toggled is returned." (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) @@ -1179,6 +1225,7 @@ the actual number of articles toggled is returned." (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))) @@ -1296,7 +1343,7 @@ The following commands are available: (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 @@ -1465,7 +1512,11 @@ The following commands are available: (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." @@ -1700,7 +1751,7 @@ The following commands are available: (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) diff --git a/lisp/gnus-art.el b/lisp/gnus-art.el index 5a8ab62..0dad544 100644 --- a/lisp/gnus-art.el +++ b/lisp/gnus-art.el @@ -1,5 +1,5 @@ ;;; 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 @@ -32,6 +32,7 @@ (require 'gnus-sum) (require 'gnus-spec) (require 'gnus-int) +(require 'gnus-win) (require 'mm-bodies) (require 'mail-parse) (require 'mm-decode) @@ -134,7 +135,13 @@ "^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." @@ -168,15 +175,23 @@ this list." (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) @@ -209,20 +224,26 @@ regexp. If it matches, the text in question is not a signature." ;; 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) @@ -392,6 +413,7 @@ Gnus provides the following functions: * 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 @@ -399,6 +421,7 @@ Gnus provides the following functions: (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))) @@ -620,7 +643,8 @@ displayed by the first non-nil matching CONTENT face." (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) @@ -661,7 +685,17 @@ displayed by the first non-nil matching CONTENT face." :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)) @@ -765,7 +799,7 @@ used." (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) @@ -854,13 +888,6 @@ See the manual for details." :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. @@ -987,6 +1014,20 @@ See the manual for details." :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. @@ -999,7 +1040,8 @@ See the manual for details." (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. @@ -1023,13 +1065,47 @@ See the manual for details." :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. @@ -1091,6 +1167,7 @@ It is a string, such as \"PGP\". If nil, ask user." (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 @@ -1102,8 +1179,6 @@ It is a string, such as \"PGP\". If nil, ask user." (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) @@ -1120,6 +1195,9 @@ It is a string, such as \"PGP\". If nil, ask user." (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) @@ -1130,10 +1208,14 @@ It is a string, such as \"PGP\". If nil, ask user." (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) @@ -1161,6 +1243,34 @@ Initialized from `text-mode-syntax-table.") (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) @@ -1178,14 +1288,13 @@ Initialized from `text-mode-syntax-table.") (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) @@ -1269,7 +1378,7 @@ Initialized from `text-mode-syntax-table.") ;; `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 @@ -1284,7 +1393,7 @@ Initialized from `text-mode-syntax-table.") (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)))))))) @@ -1508,6 +1617,53 @@ MAP is an alist where the elements are on the form (\"from\" \"to\")." (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) @@ -1516,7 +1672,7 @@ MAP is an alist where the elements are on the form (\"from\" \"to\")." (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)) @@ -1569,89 +1725,52 @@ MAP is an alist where the elements are on the form (\"from\" \"to\")." (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." @@ -1726,11 +1845,35 @@ If PROMPT (the prefix), prompt for a coding system to use." (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) @@ -1745,6 +1888,8 @@ or not." (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 @@ -1754,10 +1899,11 @@ or not." (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) @@ -1772,6 +1918,8 @@ If FORCE, decode the article whether it is marked as base64 not." (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 @@ -1795,9 +1943,10 @@ If FORCE, decode the article whether it is marked as base64 not." (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) @@ -1811,6 +1960,8 @@ If FORCE, decode the article whether it is marked as base64 not." (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) @@ -1819,7 +1970,9 @@ If FORCE, decode the article whether it is marked as base64 not." (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)))))))) @@ -1857,7 +2010,7 @@ The `gnus-list-identifiers' variable specifies what to do." (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) @@ -1897,7 +2050,7 @@ always hide." "\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) @@ -1946,11 +2099,11 @@ always hide." (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. @@ -1963,7 +2116,8 @@ always hide." (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." @@ -2023,10 +2177,10 @@ Point is left at the beginning of the narrowed-to region." (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." @@ -2115,7 +2269,7 @@ Put point at the beginning of the signature separator." (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 @@ -2155,7 +2309,8 @@ Originally it is hide instead of DUMMY." '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)) @@ -2177,7 +2332,7 @@ should replace the \"Date:\" one, or should be added below it." (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) @@ -2203,8 +2358,8 @@ should replace the \"Date:\" one, or should be added below it." (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))) @@ -2235,7 +2390,7 @@ should replace the \"Date:\" one, or should be added below it." (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) @@ -2448,15 +2603,15 @@ This format is defined by the `gnus-article-time-format' variable." 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." @@ -2657,7 +2812,7 @@ Directory to save to is default to `gnus-article-save-directory'." 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)) @@ -2699,13 +2854,20 @@ The directory to save in defaults to `gnus-article-save-directory'." (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) @@ -2758,7 +2920,9 @@ If variable `gnus-use-long-file-name' is non-nil, it is (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) @@ -2843,6 +3007,12 @@ If variable `gnus-use-long-file-name' is non-nil, it is (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) @@ -2853,7 +3023,7 @@ If variable `gnus-use-long-file-name' is non-nil, it is (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)) @@ -2864,6 +3034,7 @@ If variable `gnus-use-long-file-name' is non-nil, it is (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 @@ -2973,7 +3144,7 @@ If variable `gnus-use-long-file-name' is non-nil, it is ;; 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 @@ -3011,6 +3182,7 @@ commands: (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) @@ -3069,7 +3241,7 @@ commands: ;; 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)) @@ -3199,7 +3371,8 @@ If ALL-HEADERS is non-nil, no headers are hidden." (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)) @@ -3239,6 +3412,7 @@ If ALL-HEADERS is non-nil, no headers are hidden." (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"))) @@ -3291,17 +3465,18 @@ If ALL-HEADERS is non-nil, no headers are hidden." (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) @@ -3330,12 +3505,14 @@ If ALL-HEADERS is non-nil, no headers are hidden." (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 @@ -3409,14 +3586,14 @@ If ALL-HEADERS is non-nil, no headers are hidden." (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))) @@ -3440,6 +3617,31 @@ If ALL-HEADERS is non-nil, no headers are hidden." (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)) @@ -3463,7 +3665,7 @@ If ALL-HEADERS is non-nil, no headers are hidden." (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 @@ -3475,7 +3677,8 @@ If ALL-HEADERS is non-nil, no headers are hidden." (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))) @@ -3488,7 +3691,7 @@ If ALL-HEADERS is non-nil, no headers are hidden." (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))))) @@ -3510,7 +3713,7 @@ If ALL-HEADERS is non-nil, no headers are hidden." (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))) @@ -3633,7 +3836,7 @@ In no internal viewer is available, use an external viewer." 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)) @@ -3643,7 +3846,8 @@ In no internal viewer is available, use an external viewer." ;; 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. @@ -3654,7 +3858,8 @@ In no internal viewer is available, use an external viewer." 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 @@ -3669,12 +3874,9 @@ In no internal viewer is available, use an external viewer." (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 @@ -3692,8 +3894,8 @@ In no internal viewer is available, use an external viewer." (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)) @@ -3820,12 +4022,10 @@ In no internal viewer is available, use an external viewer." ;;;!!! 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 @@ -3857,7 +4057,9 @@ In no internal viewer is available, use an external viewer." "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") @@ -3907,11 +4109,16 @@ In no internal viewer is available, use an external viewer." (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." @@ -4015,6 +4222,39 @@ In no internal viewer is available, use an external viewer." (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 @@ -4029,13 +4269,37 @@ In no internal viewer is available, use an external viewer." (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) @@ -4059,7 +4323,8 @@ Provided for backwards compatibility." ;; 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) @@ -4220,61 +4485,61 @@ Argument LINES specifies lines to be scrolled down." (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) @@ -4290,7 +4555,7 @@ Argument LINES specifies lines to be scrolled down." (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." @@ -4303,10 +4568,10 @@ Argument LINES specifies lines to be scrolled down." (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: ")))) @@ -4324,10 +4589,10 @@ Argument LINES specifies lines to be scrolled down." (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: ")))) @@ -4468,7 +4733,9 @@ If given a prefix, show the hidden text instead." (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)) @@ -4522,7 +4789,7 @@ If given a prefix, show the hidden text instead." (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)))))) @@ -4552,21 +4819,18 @@ If given a prefix, show the hidden text instead." "\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. @@ -4675,7 +4939,7 @@ groups." ;;; 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) @@ -4694,6 +4958,9 @@ groups." ("\\( \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... ("]*\\)>" 0 t gnus-button-embedded-url 1) ;; Raw URLs. @@ -4720,7 +4987,7 @@ variable it the real callback function." (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<>,()\"]+" @@ -4766,7 +5033,7 @@ call it with the value of the `gnus-data' text property." (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 @@ -4982,14 +5249,19 @@ specified by `gnus-button-alist'." (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. @@ -5036,7 +5308,7 @@ specified by `gnus-button-alist'." (when (looking-at "//\\([^/]+\\)/") (setq server (match-string 1)) (goto-char (match-end 0))) - + (cond ((looking-at "\\(.*@.*\\)") (setq message-id (match-string 1))) @@ -5064,6 +5336,18 @@ specified by `gnus-button-alist'." (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 @@ -5075,8 +5359,10 @@ specified by `gnus-button-alist'." (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) @@ -5084,80 +5370,50 @@ specified by `gnus-button-alist'." (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) @@ -5194,7 +5450,7 @@ forbidden in URL encoding." "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))) @@ -5202,7 +5458,7 @@ forbidden in URL encoding." "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))) @@ -5218,7 +5474,7 @@ forbidden in URL encoding." "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))) @@ -5226,7 +5482,7 @@ forbidden in URL encoding." "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))) @@ -5356,9 +5612,9 @@ For example: (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) @@ -5453,21 +5709,25 @@ For example: (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) @@ -5483,13 +5743,15 @@ For example: 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) @@ -5562,13 +5824,15 @@ For example: (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)) diff --git a/lisp/gnus-bcklg.el b/lisp/gnus-bcklg.el index 3fca805..f95fcee 100644 --- a/lisp/gnus-bcklg.el +++ b/lisp/gnus-bcklg.el @@ -1,5 +1,6 @@ ;;; 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 ;; Keywords: news @@ -55,6 +56,7 @@ (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 diff --git a/lisp/gnus-cache.el b/lisp/gnus-cache.el index 4916331..574821e 100644 --- a/lisp/gnus-cache.el +++ b/lisp/gnus-cache.el @@ -1,5 +1,5 @@ ;;; 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 @@ -160,11 +160,7 @@ it's not cached." (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 @@ -209,7 +205,7 @@ it's not cached." (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)))))) @@ -235,7 +231,7 @@ it's not cached." (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) @@ -307,7 +303,7 @@ it's not cached." ;; 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) @@ -374,8 +370,16 @@ Returns the list of articles removed." (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. @@ -490,9 +494,9 @@ Returns the list of articles removed." (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") @@ -535,7 +539,7 @@ Returns the list of articles removed." (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)) @@ -605,6 +609,24 @@ $ emacs -batch -l ~/.emacs -l gnus -f gnus-jog-cache" ;; 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." @@ -679,6 +701,20 @@ 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 diff --git a/lisp/gnus-cite.el b/lisp/gnus-cite.el index 73c4bef..6a09a47 100644 --- a/lisp/gnus-cite.el +++ b/lisp/gnus-cite.el @@ -1,6 +1,6 @@ -;;; 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 @@ -471,8 +471,8 @@ always hide." 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) @@ -510,6 +510,7 @@ always hide." (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) @@ -548,14 +549,20 @@ means show, nil means toggle." (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) @@ -953,14 +960,20 @@ See also the documentation for `gnus-article-highlight-citation'." (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. diff --git a/lisp/gnus-cus.el b/lisp/gnus-cus.el index 0b6d704..6df3ffa 100644 --- a/lisp/gnus-cus.el +++ b/lisp/gnus-cus.el @@ -1,6 +1,6 @@ ;;; 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 ;; Keywords: news @@ -34,10 +34,6 @@ ;;; 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. @@ -155,10 +151,10 @@ days (not necessarily an integer) or the symbols `never' or `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.") @@ -182,15 +178,25 @@ you to put the admin address somewhere convenient.") (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.") @@ -199,13 +205,13 @@ 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.") @@ -214,14 +220,14 @@ 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.")) @@ -233,10 +239,15 @@ DOC is a documentation string for the parameter.") (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 @@ -266,7 +277,7 @@ DOC is a documentation string for 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))))) @@ -646,7 +657,7 @@ When called interactively, FILE defaults to the current score file. 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) diff --git a/lisp/gnus-delay.el b/lisp/gnus-delay.el new file mode 100644 index 0000000..c7652da --- /dev/null +++ b/lisp/gnus-delay.el @@ -0,0 +1,187 @@ +;;; gnus-delay.el --- Delayed posting of articles + +;; Copyright (C) 2001, 2002 Free Software Foundation, Inc. + +;; Author: Kai Großjohann +;; 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: + +* for 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 diff --git a/lisp/gnus-demon.el b/lisp/gnus-demon.el index d647928..2c73b37 100644 --- a/lisp/gnus-demon.el +++ b/lisp/gnus-demon.el @@ -150,32 +150,32 @@ time Emacs has been idle for IDLE `gnus-demon-timestep's." (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))))) diff --git a/lisp/gnus-diary.el b/lisp/gnus-diary.el new file mode 100644 index 0000000..2e434c6 --- /dev/null +++ b/lisp/gnus-diary.el @@ -0,0 +1,460 @@ +;;; gnus-diary.el --- Wrapper around the NNDiary Gnus backend + +;; Copyright (C) 1999-2001 Didier Verna. + +;; Author: Didier Verna +;; Maintainer: Didier Verna +;; 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 ": ") 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: +;; +;; : +;; +;; 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 diff --git a/lisp/gnus-draft.el b/lisp/gnus-draft.el index 47b0939..9b18989 100644 --- a/lisp/gnus-draft.el +++ b/lisp/gnus-draft.el @@ -1,5 +1,5 @@ ;;; 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 @@ -94,13 +94,18 @@ (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) @@ -118,8 +123,8 @@ (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))))) @@ -128,7 +133,7 @@ "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")) @@ -171,7 +176,7 @@ (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") @@ -185,8 +190,8 @@ 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))))))) @@ -231,14 +236,21 @@ (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." diff --git a/lisp/gnus-eform.el b/lisp/gnus-eform.el index 9fe7242..042f8c3 100644 --- a/lisp/gnus-eform.el +++ b/lisp/gnus-eform.el @@ -1,5 +1,5 @@ ;;; 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 @@ -114,7 +114,9 @@ of the buffer." "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))) diff --git a/lisp/gnus-ems.el b/lisp/gnus-ems.el index 62c2695..61ab874 100644 --- a/lisp/gnus-ems.el +++ b/lisp/gnus-ems.el @@ -70,6 +70,12 @@ 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 @@ -84,7 +90,10 @@ (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) @@ -215,8 +224,8 @@ "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 @@ -234,10 +243,6 @@ for XEmacs." (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) @@ -278,8 +283,29 @@ for XEmacs." (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 diff --git a/lisp/gnus-gl.el b/lisp/gnus-gl.el index a17e0ce..4b5ba19 100644 --- a/lisp/gnus-gl.el +++ b/lisp/gnus-gl.el @@ -1,6 +1,6 @@ ;;; 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 @@ -131,7 +131,7 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (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 "" @@ -510,11 +510,11 @@ recommend using both scores and grouplens predictions together." ;; 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 ?|) @@ -632,10 +632,10 @@ recommend using both scores and grouplens predictions together." (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")) diff --git a/lisp/gnus-group.el b/lisp/gnus-group.el index 1c44e11..fe15317 100644 --- a/lisp/gnus-group.el +++ b/lisp/gnus-group.el @@ -1,5 +1,5 @@ ;;; 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 @@ -126,17 +126,22 @@ the most significant sort function should be the last function in the 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. @@ -153,6 +158,7 @@ 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\") @@ -200,12 +206,6 @@ with some simple extensions: :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) @@ -295,52 +295,52 @@ variable." (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 @@ -402,21 +402,23 @@ ticked: The number of ticked articles." :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")))) @@ -427,7 +429,7 @@ in which case `gnus-group-jump-to-group' offers \"Group: nnml:\" 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. @@ -541,6 +543,7 @@ simple manner.") "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 @@ -590,6 +593,10 @@ simple manner.") "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 @@ -841,6 +848,9 @@ simple manner.") ["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 @@ -849,7 +859,7 @@ simple manner.") (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 @@ -858,11 +868,16 @@ simple manner.") ["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] @@ -957,6 +972,7 @@ The following commands are available: (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 "")) @@ -998,7 +1014,7 @@ The following commands are available: (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)) @@ -1012,8 +1028,9 @@ The following commands are available: 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)) @@ -1334,7 +1351,9 @@ if it is a string, only list groups matching REGEXP." (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) @@ -1364,9 +1383,13 @@ if it is a string, only list groups matching REGEXP." (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)))) @@ -1772,6 +1795,7 @@ group." (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") @@ -1861,7 +1885,8 @@ Return the name of the group if selection was successful." (,(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 @@ -2138,7 +2163,7 @@ doing the deletion." (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 @@ -2237,7 +2262,17 @@ and NEW-NAME will be prompted for." (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." @@ -2298,20 +2333,33 @@ and NEW-NAME will be prompted for." (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) @@ -2609,6 +2657,7 @@ If REVERSE (the prefix), reverse the sorting order." (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)) @@ -2675,7 +2724,9 @@ If REVERSE, sort in reverse order." (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) @@ -2773,10 +2824,10 @@ sort in reverse order." (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)))) @@ -2822,13 +2873,22 @@ sort in reverse order." (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)))) @@ -2888,31 +2948,34 @@ If ALL is non-nil, all articles are marked as read. 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." @@ -3582,7 +3645,7 @@ group." (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 @@ -3834,7 +3897,7 @@ or `gnus-group-catchup-group-hook'." "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)))) @@ -3942,7 +4005,7 @@ This command may read the active file." (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)) diff --git a/lisp/gnus-int.el b/lisp/gnus-int.el index e7462e9..fbb50db 100644 --- a/lisp/gnus-int.el +++ b/lisp/gnus-int.el @@ -110,7 +110,8 @@ If CONFIRM is non-nil, the user will be asked for an NNTP server." "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))) @@ -125,11 +126,14 @@ If it is down, start it up (again)." (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." @@ -179,9 +183,13 @@ If it is down, start it up (again)." 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) diff --git a/lisp/gnus-kill.el b/lisp/gnus-kill.el index dfed289..b134be9 100644 --- a/lisp/gnus-kill.el +++ b/lisp/gnus-kill.el @@ -1,5 +1,5 @@ ;;; 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 @@ -357,16 +357,16 @@ If NEWSGROUP is nil, return the global kill file instead." (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. @@ -398,7 +398,7 @@ Returns the number of articles marked as read." 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 @@ -641,18 +641,30 @@ If optional 2nd argument UNREAD is non-nil, articles which are 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))) diff --git a/lisp/gnus-logic.el b/lisp/gnus-logic.el index 03b1c1c..13c9a20 100644 --- a/lisp/gnus-logic.el +++ b/lisp/gnus-logic.el @@ -1,5 +1,5 @@ ;;; 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 @@ -227,4 +227,4 @@ (provide 'gnus-logic) -;;; gnus-logic.el ends here. +;;; gnus-logic.el ends here diff --git a/lisp/gnus-ml.el b/lisp/gnus-ml.el index b2f57df..41f85ae 100644 --- a/lisp/gnus-ml.el +++ b/lisp/gnus-ml.el @@ -1,6 +1,6 @@ ;;; 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 ;; Keywords: news @@ -67,7 +67,7 @@ ;;;###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 @@ -75,7 +75,7 @@ "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 @@ -84,7 +84,7 @@ If FORCE is non-nil, replace the old ones." (gnus-message 1 "to-list is non-nil.") (if (string-match "]*\\)>" 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.")))) @@ -109,8 +109,8 @@ If FORCE is non-nil, replace the old ones." (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)) @@ -119,7 +119,7 @@ If FORCE is non-nil, replace the old ones." (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)) @@ -128,7 +128,7 @@ If FORCE is non-nil, replace the old ones." (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)) @@ -137,7 +137,7 @@ If FORCE is non-nil, replace the old ones." (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)) @@ -146,7 +146,7 @@ If FORCE is non-nil, replace the old ones." (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)) @@ -156,10 +156,10 @@ If FORCE is non-nil, replace the old ones." "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))) @@ -174,7 +174,7 @@ If FORCE is non-nil, replace the old ones." (subject "None") (body "") ) - (cond + (cond ((string-match "]*\\)>" address) (let ((args (match-string 1 address))) (cond ; with param @@ -187,9 +187,9 @@ If FORCE is non-nil, replace the old ones." (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 @@ -20,6 +21,10 @@ ;; 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) @@ -92,8 +97,8 @@ gnus-group-split is a valid value for nnmail-split-methods." ;;;###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\) @@ -139,7 +144,7 @@ Calling (gnus-group-split-fancy nil nil \"mail.misc\") returns: \(| (& (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) @@ -196,12 +201,9 @@ Calling (gnus-group-split-fancy nil nil \"mail.misc\") returns: (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) @@ -223,3 +225,5 @@ Calling (gnus-group-split-fancy nil nil \"mail.misc\") returns: split)) (provide 'gnus-mlspl) + +;;; gnus-mlspl.el ends here diff --git a/lisp/gnus-msg.el b/lisp/gnus-msg.el index c5dc6ec..af72688 100644 --- a/lisp/gnus-msg.el +++ b/lisp/gnus-msg.el @@ -38,23 +38,23 @@ "*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 @@ -63,18 +63,25 @@ can also be a list of group names. 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: @@ -90,19 +97,45 @@ Thank you. " "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)) @@ -147,6 +180,8 @@ use this option with care." (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. ======================================== @@ -182,6 +217,7 @@ Thank you for your help in stamping out bugs. (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 @@ -198,6 +234,8 @@ Thank you for your help in stamping out bugs. "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 @@ -227,7 +265,16 @@ Thank you for your help in stamping out bugs. (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) @@ -242,11 +289,17 @@ Thank you for your help in stamping out bugs. (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) @@ -281,19 +334,27 @@ Gcc: header for archiving purposes." ;; 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 @@ -362,15 +423,47 @@ If ARG is 1, prompt for a group name to find the posting style." (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 @@ -382,10 +475,78 @@ If ARG is 1, prompt for a group 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. @@ -523,14 +684,18 @@ header line with the old Message-ID." (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 @@ -562,8 +727,7 @@ header line with the old Message-ID." 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))) @@ -596,10 +760,11 @@ header line with the old Message-ID." (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")))) @@ -607,28 +772,31 @@ header line with the old Message-ID." (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))) @@ -668,13 +836,14 @@ If SILENT, don't prompt the user." ;; 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)))) @@ -693,7 +862,8 @@ If SILENT, don't prompt the user." " " (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) @@ -702,7 +872,7 @@ If SILENT, don't prompt the user." (match-string 3 emacs-version) "") (if (boundp 'xemacs-codename) - (concat " (" xemacs-codename ")") + (concat " (" xemacs-codename ", " system-configuration ")") ""))) (t emacs-version)))) @@ -739,7 +909,7 @@ If VERY-WIDE, make a very wide reply." (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 @@ -757,6 +927,24 @@ The original article will be yanked." (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 @@ -789,40 +977,45 @@ The original article will be 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." @@ -897,12 +1090,6 @@ The current group name will be inserted at \"%s\".") (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) @@ -1017,6 +1204,7 @@ If YANK is non-nil, include the original article." (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>")) @@ -1126,65 +1314,86 @@ this is a reply." ;;; 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 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'." @@ -1280,10 +1489,10 @@ this is a reply." ;;; 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) @@ -1362,7 +1571,8 @@ this is a reply." (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 @@ -1394,19 +1604,21 @@ this is a reply." (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. diff --git a/lisp/gnus-picon.el b/lisp/gnus-picon.el index 856c5f3..5cb616d 100644 --- a/lisp/gnus-picon.el +++ b/lisp/gnus-picon.el @@ -1,6 +1,6 @@ ;;; 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 @@ -25,729 +25,237 @@ ;;; 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: "key = value" -;; 2 - a "

" 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 "" - (regexp-quote name) - " *= * *\\([^ <][^<]*\\) *") - 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 "

[ \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 "
")) - (goto-char (point-min)) - (setq types gnus-picons-file-suffixes) - (while (and types - (not (re-search-forward - (concat " ;; Keywords: news @@ -348,7 +349,7 @@ modified." range item selector) (while (or item1 item2) (setq selector - (cond + (cond ((null item1) nil) ((null item2) t) ((and (numberp item1) (numberp item2)) (< item1 item2)) @@ -358,30 +359,30 @@ modified." (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)) diff --git a/lisp/gnus-salt.el b/lisp/gnus-salt.el index 2a6acc9..f277591 100644 --- a/lisp/gnus-salt.el +++ b/lisp/gnus-salt.el @@ -1,6 +1,7 @@ ;;; 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 ;; Keywords: news @@ -30,6 +31,7 @@ (require 'gnus) (require 'gnus-sum) +(require 'gnus-win) ;;; ;;; gnus-pick-mode @@ -64,7 +66,7 @@ summary buffers.") :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 @@ -87,22 +89,22 @@ It accepts the same format specs that `gnus-summary-line-format' does." (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. @@ -153,11 +155,11 @@ If given a prefix, mark all unpicked articles as read." (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 @@ -228,7 +230,7 @@ This must be bound to a button-down mouse event." (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)) @@ -240,7 +242,7 @@ This must be bound to a button-down mouse event." (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)) @@ -251,61 +253,61 @@ This must be bound to a button-down mouse event." ;; (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 () @@ -338,9 +340,9 @@ This must be bound to a button-down mouse event." (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." @@ -470,9 +472,9 @@ Two predefined functions are available: (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." @@ -553,7 +555,7 @@ Two predefined functions are available: (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 @@ -565,7 +567,7 @@ Two predefined functions are available: (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 @@ -666,6 +668,8 @@ Two predefined functions are available: (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 @@ -696,8 +700,8 @@ Two predefined functions are available: (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)))))) @@ -835,6 +839,13 @@ Two predefined functions are available: (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)) @@ -853,11 +864,11 @@ Two predefined functions are available: (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)) @@ -870,7 +881,7 @@ Two predefined functions are available: (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 @@ -896,6 +907,7 @@ Two predefined functions are available: ("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))) @@ -926,7 +938,8 @@ Two predefined functions are available: ("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) diff --git a/lisp/gnus-score.el b/lisp/gnus-score.el index d7f457d..fe7db38 100644 --- a/lisp/gnus-score.el +++ b/lisp/gnus-score.el @@ -32,6 +32,7 @@ (require 'gnus) (require 'gnus-sum) (require 'gnus-range) +(require 'gnus-win) (require 'message) (require 'score-mode) @@ -47,7 +48,7 @@ score files in the \"/ftp.some-where:/pub/score\" directory. (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)) @@ -59,10 +60,10 @@ Each element of this alist should be of the form 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)))) @@ -75,10 +76,10 @@ If the name of a group is matched by REGEXP, the corresponding scorefiles 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)))) @@ -101,9 +102,9 @@ files do not actually have to exist. 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. @@ -740,7 +741,7 @@ used as score." (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. @@ -1148,7 +1149,7 @@ EXTRA is the possible non-standard header." (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))) @@ -1433,7 +1434,7 @@ EXTRA is the possible non-standard header." (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 @@ -1494,7 +1495,7 @@ EXTRA is the possible non-standard header." (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. @@ -1502,7 +1503,7 @@ THREAD is expected to contain a list of the form `(PARENT [CHILD1 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) @@ -1520,7 +1521,7 @@ GNUS-NEWSGROUP-SCORED is adjusted by SCORE-ADJUST." 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 @@ -1874,8 +1875,8 @@ score in GNUS-NEWSGROUP-SCORED by SCORE." ;; 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) @@ -1939,10 +1940,10 @@ score in GNUS-NEWSGROUP-SCORED by SCORE." (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) @@ -1952,7 +1953,7 @@ score in GNUS-NEWSGROUP-SCORED by SCORE." ;; 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 @@ -2567,7 +2568,7 @@ GROUP using BNews sys file syntax." ;; 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)))) @@ -2604,10 +2605,10 @@ GROUP using BNews sys file syntax." ;; 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)) @@ -2687,7 +2688,7 @@ Destroys the 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 @@ -2744,7 +2745,8 @@ The list is determined from the variable gnus-score-file-alist." (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. @@ -2851,9 +2853,10 @@ If ADAPT, return the home adaptive file instead." (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." diff --git a/lisp/gnus-setup.el b/lisp/gnus-setup.el index 307aaaf..7ad8883 100644 --- a/lisp/gnus-setup.el +++ b/lisp/gnus-setup.el @@ -1,6 +1,7 @@ ;;; 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 ;; Keywords: news @@ -35,7 +36,7 @@ (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.") diff --git a/lisp/gnus-sieve.el b/lisp/gnus-sieve.el new file mode 100644 index 0000000..36c99d0 --- /dev/null +++ b/lisp/gnus-sieve.el @@ -0,0 +1,238 @@ +;;; gnus-sieve.el --- Utilities to manage sieve scripts for Gnus +;; Copyright (C) 2001 Free Software Foundation, Inc. + +;; Author: NAGY Andras , +;; Simon Josefsson + +;; 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 diff --git a/lisp/gnus-spec.el b/lisp/gnus-spec.el index 0b15c2c..92a9e80 100644 --- a/lisp/gnus-spec.el +++ b/lisp/gnus-spec.el @@ -1,5 +1,5 @@ -;;; 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 @@ -30,6 +30,11 @@ (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) @@ -120,10 +125,11 @@ (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.") @@ -131,7 +137,7 @@ (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) @@ -169,6 +175,8 @@ ;; 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)) @@ -176,8 +184,8 @@ ;; 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) @@ -246,36 +254,86 @@ '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) @@ -287,6 +345,27 @@ (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 @@ -294,50 +373,78 @@ ;; 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) @@ -347,7 +454,7 @@ (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) @@ -359,7 +466,8 @@ 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. @@ -400,10 +508,18 @@ 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)) @@ -421,20 +537,27 @@ (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))) @@ -448,16 +571,18 @@ (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. @@ -522,7 +647,7 @@ If PROPS, insert the result." (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) diff --git a/lisp/gnus-srvr.el b/lisp/gnus-srvr.el index 729899a..dbf3776 100644 --- a/lisp/gnus-srvr.el +++ b/lisp/gnus-srvr.el @@ -34,10 +34,17 @@ (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. @@ -48,16 +55,20 @@ The following specs are understood: %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. @@ -149,13 +160,69 @@ The following specs are understood: "\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. \\ For more in-depth information on this mode, read the manual -(`\\[gnus-info-find-node]'). +\(`\\[gnus-info-find-node]'). The following commands are available: @@ -173,19 +240,25 @@ 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)) @@ -568,7 +641,7 @@ The following commands are available: ["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))) @@ -641,7 +714,7 @@ The following commands are available: 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)) @@ -654,20 +727,18 @@ The following commands are available: (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) @@ -836,7 +907,7 @@ buffer. (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"))) @@ -849,4 +920,4 @@ buffer. (provide 'gnus-srvr) -;;; gnus-srvr.el ends here. +;;; gnus-srvr.el ends here diff --git a/lisp/gnus-start.el b/lisp/gnus-start.el index 22e0096..01d5351 100644 --- a/lisp/gnus-start.el +++ b/lisp/gnus-start.el @@ -229,7 +229,7 @@ not match this regexp will be removed before saving the list." (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 ) "\\|") @@ -303,7 +303,7 @@ hierarchy in its entirety." :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. @@ -396,15 +396,24 @@ Can be used to turn version control on or off." :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) @@ -441,12 +450,16 @@ Can be used to turn version control on or off." (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 @@ -897,10 +910,17 @@ If LEVEL is non-nil, the news will be set up at level LEVEL." ;; 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. @@ -951,6 +971,12 @@ If LEVEL is non-nil, the news will be set up at level LEVEL." 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) @@ -962,12 +988,7 @@ If LEVEL is non-nil, the news will be set up at level 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. @@ -1018,7 +1039,7 @@ for new groups, and subscribe the new groups as zombies." (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 @@ -1083,7 +1104,8 @@ for new groups, and subscribe the new groups as zombies." (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) @@ -1093,7 +1115,6 @@ for new groups, and subscribe the new groups as zombies." 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 @@ -1157,10 +1178,8 @@ for new groups, and subscribe the new groups as zombies." (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) @@ -1169,27 +1188,27 @@ for new groups, and subscribe the new groups as zombies." (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) @@ -1197,7 +1216,9 @@ for new groups, and subscribe the new groups as zombies." 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")))))) @@ -1359,7 +1380,9 @@ newsgroup." (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 @@ -1430,24 +1453,27 @@ newsgroup." (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 @@ -1575,7 +1601,7 @@ newsgroup." (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 @@ -1616,8 +1642,8 @@ newsgroup." (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 @@ -1640,22 +1666,22 @@ newsgroup." (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"))) @@ -1784,13 +1810,15 @@ newsgroup." ;; 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) @@ -2067,17 +2095,20 @@ If FORCE is non-nil, the .newsrc file is read." ;; 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) @@ -2438,7 +2469,7 @@ If FORCE is non-nil, the .newsrc file is read." (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 @@ -2564,7 +2595,7 @@ If FORCE is non-nil, the .newsrc file is read." (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))))) diff --git a/lisp/gnus-sum.el b/lisp/gnus-sum.el index 7d8f6f5..7960b8d 100644 --- a/lisp/gnus-sum.el +++ b/lisp/gnus-sum.el @@ -36,9 +36,8 @@ (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) @@ -199,6 +198,20 @@ If this variable is nil, scoring will be disabled." :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' @@ -264,25 +277,30 @@ equal will be included." :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. @@ -360,7 +378,7 @@ this variable specifies group names." (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) @@ -420,22 +438,32 @@ this variable specifies group names." :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) @@ -485,7 +513,7 @@ this variable specifies group names." :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) @@ -672,7 +700,7 @@ This variable is local to the summary buffers." (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) @@ -783,6 +811,14 @@ automatically when it is selected." :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 @@ -791,43 +827,43 @@ automatically when it is selected." (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)) @@ -840,10 +876,12 @@ how those summary lines are displayed, by editing the face field. 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))) @@ -883,7 +921,7 @@ default charset will be used instead." :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. @@ -892,7 +930,7 @@ default charset will be used instead." :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 "\ @@ -964,8 +1002,14 @@ that were fetched. Say, for nnultimate groups." :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) @@ -998,6 +1042,7 @@ that were fetched. Say, for nnultimate groups." (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) @@ -1035,7 +1080,8 @@ that were fetched. Say, for nnultimate groups." (?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) @@ -1043,7 +1089,10 @@ that were fetched. Say, for nnultimate groups." (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).") @@ -1122,6 +1171,9 @@ 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.") @@ -1143,6 +1195,15 @@ the type of the variable (string, integer, character, etc).") (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.") @@ -1180,10 +1241,12 @@ the type of the variable (string, integer, character, etc).") 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 @@ -1205,11 +1268,23 @@ the type of the variable (string, integer, character, etc).") 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)) @@ -1220,13 +1295,13 @@ the type of the variable (string, integer, character, etc).") '(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))") @@ -1245,7 +1320,7 @@ For example: (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 @@ -1260,8 +1335,8 @@ For example: ;; 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)))) @@ -1476,6 +1551,7 @@ increase the score of each group you read." 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 @@ -1521,6 +1597,7 @@ increase the score of each group you read." "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 @@ -1548,6 +1625,7 @@ increase the score of each group you read." "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 @@ -1647,6 +1725,9 @@ increase the score of each group you 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 @@ -1671,6 +1752,13 @@ increase the score of each group you read." "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 @@ -1731,6 +1819,7 @@ increase the score of each group you read." "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) @@ -1753,49 +1842,50 @@ increase the score of each group you read." (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] @@ -1804,181 +1894,191 @@ increase the score of each group you read." ["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) @@ -1989,138 +2089,140 @@ increase the score of each group you read." (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))) @@ -2403,7 +2505,7 @@ The following commands are available: (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))) @@ -2465,7 +2567,7 @@ The following commands are available: (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)))))) @@ -2605,9 +2707,6 @@ marks of articles." ;; 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"))) @@ -2616,6 +2715,8 @@ marks of articles." (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." @@ -2671,7 +2772,7 @@ display only a single character." ;; 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) @@ -2685,9 +2786,24 @@ display only a single character." (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." @@ -2831,32 +2947,31 @@ buffer that was in action when the last article was fetched." (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 @@ -2871,16 +2986,23 @@ buffer that was in action when the last article was fetched." (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 @@ -2895,7 +3017,6 @@ buffer that was in action when the last article was fetched." (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)) @@ -2903,8 +3024,9 @@ buffer that was in action when the last article was fetched." (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)) @@ -2937,7 +3059,7 @@ buffer that was in action when the last article was fetched." (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)) @@ -2952,7 +3074,7 @@ buffer that was in action when the last article was fetched." 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 . + ;; Fix by Luc Van Eycken . (cond ((not (listp thread)) 1) @@ -2978,6 +3100,7 @@ the thread are to be displayed." (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) @@ -2985,8 +3108,9 @@ the thread are to be displayed." (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)))))))) @@ -3026,7 +3150,7 @@ If NO-DISPLAY, don't generate a summary buffer." ;; (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)) @@ -3058,10 +3182,10 @@ If NO-DISPLAY, don't generate a summary buffer." (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. @@ -3145,6 +3269,7 @@ If NO-DISPLAY, don't generate a summary buffer." (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) @@ -3152,16 +3277,8 @@ If NO-DISPLAY, don't generate a summary buffer." 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)) @@ -3178,6 +3295,22 @@ If NO-DISPLAY, don't generate a summary buffer." (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) @@ -3222,7 +3355,7 @@ If NO-DISPLAY, don't generate a summary buffer." (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 () @@ -3357,7 +3490,7 @@ If NO-DISPLAY, don't generate a summary buffer." (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))) @@ -3679,7 +3812,7 @@ the id of the parent article (if any)." (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)))) @@ -3695,7 +3828,7 @@ If LINE, insert the rebuilt thread starting on line LINE." (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)) @@ -4045,6 +4178,23 @@ Unscored articles will be counted as having a score of zero." (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 ...]...) ...])' @@ -4063,7 +4213,8 @@ or a straight list of headers." 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) @@ -4101,7 +4252,8 @@ or a straight list of headers." ;; 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)))) @@ -4242,7 +4394,7 @@ or a straight list of headers." (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 @@ -4256,6 +4408,10 @@ or a straight list of headers." 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 @@ -4268,13 +4424,31 @@ or a straight list of headers." ((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)) @@ -4287,7 +4461,11 @@ or a straight list of headers." (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 @@ -4383,15 +4561,15 @@ If SELECT-ARTICLES, only select those articles from GROUP." (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... @@ -4408,14 +4586,43 @@ If SELECT-ARTICLES, only select those articles from GROUP." (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 + ;; + ;; + ;; (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) @@ -4430,6 +4637,10 @@ If SELECT-ARTICLES, only select those articles from 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 @@ -4461,12 +4672,22 @@ If SELECT-ARTICLES, only select those articles from GROUP." ;; 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)) @@ -4498,6 +4719,62 @@ If SELECT-ARTICLES, only select those articles from GROUP." ;; 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 @@ -4506,11 +4783,15 @@ If SELECT-ARTICLES, only select those articles from GROUP." (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)) '<))) @@ -4533,7 +4814,9 @@ If SELECT-ARTICLES, only select those articles from GROUP." (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) @@ -4542,7 +4825,8 @@ If SELECT-ARTICLES, only select those articles from GROUP." (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)) @@ -4595,6 +4879,15 @@ If SELECT-ARTICLES, only select those articles from GROUP." (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)) @@ -4602,28 +4895,26 @@ If SELECT-ARTICLES, only select those articles from GROUP." (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))) @@ -4632,36 +4923,46 @@ If SELECT-ARTICLES, only select those articles from GROUP." (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 @@ -4680,27 +4981,23 @@ If SELECT-ARTICLES, only select those articles from GROUP." (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))) @@ -4736,12 +5033,12 @@ If WHERE is `summary', the summary mode line format will be used." ;; 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) @@ -4763,7 +5060,7 @@ If WHERE is `summary', the summary mode line format will be used." (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 @@ -4904,9 +5201,11 @@ The resulting hash table is returned, or nil if no Xrefs were found." (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 @@ -4978,22 +5277,21 @@ The resulting hash table is returned, or nil if no Xrefs were found." ;; 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 @@ -5010,7 +5308,7 @@ The resulting hash table is returned, or nil if no Xrefs were found." ;; References. (progn (goto-char p) - (if (search-forward "\nreferences: " nil t) + (if (search-forward "\nreferences:" nil t) (progn (setq end (point)) (prog1 @@ -5027,7 +5325,7 @@ The resulting hash table is returned, or nil if no Xrefs were found." ;; 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) @@ -5057,7 +5355,7 @@ The resulting hash table is returned, or nil if no Xrefs were found." ;; 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 @@ -5066,7 +5364,7 @@ The resulting hash table is returned, or nil if no Xrefs were found." (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)) @@ -5151,7 +5449,7 @@ Return a list of headers that match SEQUENCE (see (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 () @@ -5431,7 +5729,7 @@ Also do horizontal recentering." 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) @@ -5447,7 +5745,7 @@ displayed, no centering will be performed." (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)))) @@ -5676,7 +5974,7 @@ If FORCE (the prefix), also save the .newsrc file(s)." (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. @@ -5729,7 +6027,7 @@ If FORCE (the prefix), also save the .newsrc file(s)." (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. @@ -5809,7 +6107,7 @@ If FORCE (the prefix), also save the .newsrc file(s)." (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. @@ -5818,25 +6116,25 @@ The state which existed when entering the ephemeral is reset." (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) @@ -5966,7 +6264,7 @@ previous group instead." (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... @@ -6011,7 +6309,7 @@ If prefix argument NO-ARTICLE is non-nil, no article is selected initially." ;; 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." @@ -6037,6 +6335,8 @@ 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 @@ -6103,7 +6403,9 @@ If FORCE, also allow jumping to articles not currently shown." (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))) @@ -6156,7 +6458,7 @@ be displayed." (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) @@ -6174,11 +6476,11 @@ be displayed." (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) @@ -6476,6 +6778,16 @@ Return nil if there are no unread articles." (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." @@ -6487,8 +6799,20 @@ 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) @@ -6501,11 +6825,25 @@ Return nil if there are no articles." (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." @@ -6583,24 +6921,35 @@ If given a prefix, remove all limits." (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. @@ -6617,7 +6966,12 @@ articles that are younger than 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))) @@ -6640,30 +6994,48 @@ articles that are younger than AGE days." (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) @@ -6716,12 +7088,9 @@ Returns how many articles were removed." (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 @@ -6742,10 +7111,10 @@ article." (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) @@ -6923,6 +7292,7 @@ fetch-old-headers verbiage, and so on." ;; 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)) @@ -7011,6 +7381,9 @@ fetch-old-headers verbiage, and so on." (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 @@ -7246,21 +7619,21 @@ to guess what the document format is." (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) @@ -7293,7 +7666,7 @@ Obeys the standard process/prefix convention." (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)) @@ -7436,13 +7809,14 @@ fetched headers for, whether they are displayed or not." (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) @@ -7463,8 +7837,12 @@ in the comparisons." (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))) @@ -7476,9 +7854,11 @@ article. If BACKWARD (the prefix) is non-nil, search backward instead." (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: ") @@ -7491,7 +7871,7 @@ article. If BACKWARD (the prefix) is non-nil, search backward instead." (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) @@ -7520,6 +7900,13 @@ article. If BACKWARD (the prefix) is non-nil, search backward instead." (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. @@ -7534,64 +7921,86 @@ to save in." (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)))))) @@ -7599,7 +8008,9 @@ without any article massaging functions being run." (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)) @@ -7626,6 +8037,11 @@ without any article massaging functions being run." (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. @@ -7671,8 +8087,7 @@ If ARG is a negative number, hide the unwanted header lines." (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))))) @@ -7728,10 +8143,6 @@ ACTION can be either `move' (the default), `crosspost' or `copy'." (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 @@ -7743,7 +8154,7 @@ ACTION can be either `move' (the default), `crosspost' or `copy'." (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") @@ -7754,6 +8165,11 @@ ACTION can be either `move' (the default), `crosspost' or `copy'." 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)) @@ -7806,7 +8222,7 @@ ACTION can be either `move' (the default), `crosspost' or `copy'." (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 @@ -7823,7 +8239,8 @@ ACTION can be either `move' (the default), `crosspost' or `copy'." (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) @@ -7845,7 +8262,7 @@ ACTION can be either `move' (the default), `crosspost' or `copy'." (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 @@ -7882,25 +8299,26 @@ ACTION can be either `move' (the default), `crosspost' or `copy'." (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 @@ -7926,12 +8344,10 @@ ACTION can be either `move' (the default), `crosspost' or `copy'." (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) @@ -7951,10 +8367,9 @@ re-spool using this method." (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) @@ -8017,8 +8432,16 @@ latter case, they will be copied into the relevant groups." (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" @@ -8115,7 +8538,7 @@ This will be the case if the article has both been mailed and posted." (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) @@ -8198,10 +8621,10 @@ groups." (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) @@ -8222,10 +8645,10 @@ groups." (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) @@ -8251,7 +8674,7 @@ groups." "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))) @@ -8308,10 +8731,17 @@ groups." (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 @@ -8338,6 +8768,14 @@ groups." (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) @@ -8446,8 +8884,8 @@ number of articles marked is returned." (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))) @@ -8480,9 +8918,9 @@ the actual number of articles unmarked is returned." (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))))) @@ -8694,7 +9132,7 @@ Iff NO-EXPIRE, auto-expiry will be inhibited." (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))) @@ -8740,6 +9178,10 @@ Iff NO-EXPIRE, auto-expiry will be inhibited." 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) @@ -8748,7 +9190,7 @@ Iff NO-EXPIRE, auto-expiry will be inhibited." (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") @@ -8885,7 +9327,7 @@ The difference between N and the number of marks cleared is returned." (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))) @@ -8973,7 +9415,7 @@ even ticked and dormant ones." (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)) @@ -8981,13 +9423,13 @@ even ticked and dormant ones." (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." @@ -9015,11 +9457,17 @@ 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))) @@ -9036,6 +9484,18 @@ If ALL is non-nil, also mark ticked and dormant articles as read." (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") @@ -9189,6 +9649,8 @@ is non-nil or the Subject: of both articles are the same." (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))))) @@ -9488,7 +9950,9 @@ The variable `gnus-default-article-saver' specifies the saver function." (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) @@ -9512,7 +9976,10 @@ pipe those articles instead." (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. @@ -9569,6 +10036,17 @@ save those articles instead." (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: ") @@ -9576,11 +10054,11 @@ save those articles instead." (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." @@ -9655,7 +10133,7 @@ save those articles instead." (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)) @@ -9955,7 +10433,9 @@ If REVERSE, save parts that do not match TYPE." (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)))) @@ -10206,7 +10686,7 @@ returned." (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) @@ -10214,12 +10694,12 @@ returned." ;; 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 @@ -10250,9 +10730,9 @@ If ALL is a number, fetch this number of articles." (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) @@ -10263,10 +10743,10 @@ If ALL is a number, fetch this number of articles." (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)))))))) @@ -10284,7 +10764,7 @@ If ALL is a number, fetch this number of articles." (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)) @@ -10292,7 +10772,7 @@ If ALL is a number, fetch this number of articles." (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)) diff --git a/lisp/gnus-topic.el b/lisp/gnus-topic.el index 396fc77..63f08c7 100644 --- a/lisp/gnus-topic.el +++ b/lisp/gnus-topic.el @@ -164,6 +164,7 @@ with some simple extensions. (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)) @@ -199,7 +200,7 @@ If TOPIC, start with that 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. @@ -396,7 +397,7 @@ if it is t, list groups that have no unread articles. 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)))) @@ -644,7 +645,7 @@ articles in the topic and its subtopics." (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) @@ -1000,6 +1001,7 @@ articles in the topic and its subtopics." "\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 @@ -1038,6 +1040,7 @@ articles in the topic and its subtopics." "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)) @@ -1078,7 +1081,7 @@ articles in the topic and its subtopics." (> (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) @@ -1102,7 +1105,8 @@ articles in the topic and its subtopics." (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 @@ -1121,6 +1125,7 @@ articles in the topic and its subtopics." (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. @@ -1152,6 +1157,18 @@ If performed over a topic line, toggle folding the topic." (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 @@ -1435,7 +1452,7 @@ If RECURSIVE is t, unmark its subtopics too." (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)) @@ -1607,14 +1624,21 @@ If REVERSE, sort in reverse order." (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) @@ -1667,6 +1691,12 @@ If REVERSE, reverse the sorting order." (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))) diff --git a/lisp/gnus-util.el b/lisp/gnus-util.el index 174f2fb..2193f3b 100644 --- a/lisp/gnus-util.el +++ b/lisp/gnus-util.el @@ -41,10 +41,27 @@ (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) @@ -53,20 +70,20 @@ (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)) @@ -182,7 +199,18 @@ (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." @@ -193,6 +221,17 @@ (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." @@ -288,6 +327,70 @@ (yes-or-no-p prompt) (message ""))) +;; By Frank Schmitt . 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 () @@ -320,13 +423,7 @@ Cache the result as a text property stored in DATE." (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. @@ -396,7 +493,7 @@ If N, return the Nth ancestor instead." (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) @@ -405,9 +502,9 @@ If N, return the Nth ancestor instead." (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. @@ -421,10 +518,10 @@ If N, return the Nth ancestor instead." ;; 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 () @@ -478,8 +575,9 @@ If N, return the Nth ancestor instead." ;; 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)))) @@ -566,6 +664,19 @@ Bind `print-quoted' and `print-readably' to t while printing." (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." @@ -686,7 +797,8 @@ with potentially long computations." ;; 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) @@ -700,10 +812,10 @@ with potentially long computations." (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) @@ -755,7 +867,8 @@ with potentially long computations." (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)) @@ -914,7 +1027,7 @@ Entries without port tokens default to DEFAULTPORT." 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) @@ -932,7 +1045,7 @@ Return the modified alist." (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)))))) @@ -1023,6 +1136,87 @@ Return the modified alist." (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 diff --git a/lisp/gnus-uu.el b/lisp/gnus-uu.el index c9b9f0e..676c6f0 100644 --- a/lisp/gnus-uu.el +++ b/lisp/gnus-uu.el @@ -886,8 +886,6 @@ When called interactively, prompt for REGEXP." "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)) @@ -1420,7 +1418,7 @@ When called interactively, prompt for REGEXP." ;; 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) @@ -1489,7 +1487,7 @@ When called interactively, prompt for REGEXP." (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) @@ -2158,4 +2156,4 @@ If no file has been included, the user will be asked for a file." (provide 'gnus-uu) -;; gnus-uu.el ends here +;;; gnus-uu.el ends here diff --git a/lisp/gnus-vm.el b/lisp/gnus-vm.el index 53b741f..a4f5e65 100644 --- a/lisp/gnus-vm.el +++ b/lisp/gnus-vm.el @@ -1,6 +1,6 @@ ;;; 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 @@ -105,4 +105,4 @@ save those articles instead." (provide 'gnus-vm) -;;; gnus-vm.el ends here. +;;; gnus-vm.el ends here diff --git a/lisp/gnus-win.el b/lisp/gnus-win.el index dcdd179..9ac4c28 100644 --- a/lisp/gnus-win.el +++ b/lisp/gnus-win.el @@ -29,6 +29,7 @@ (eval-when-compile (require 'cl)) (require 'gnus) +(require 'gnus-util) (defgroup gnus-windows nil "Window configuration." @@ -57,6 +58,13 @@ :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 @@ -68,17 +76,6 @@ (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) @@ -145,7 +142,7 @@ ("*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 @@ -165,7 +162,10 @@ (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.") @@ -187,7 +187,6 @@ 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*") @@ -197,6 +196,11 @@ See the Gnus manual for an explanation of the syntax used.") (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 @@ -433,7 +437,7 @@ See the Gnus manual for an explanation of the syntax used.") ;; 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)) @@ -447,7 +451,7 @@ See the Gnus manual for an explanation of the syntax used.") ;; 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. @@ -462,6 +466,7 @@ See the Gnus manual for an explanation of the syntax used.") (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)))))))) @@ -516,7 +521,7 @@ should have point." (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))) @@ -551,6 +556,27 @@ should have point." (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 diff --git a/lisp/gnus-xmas.el b/lisp/gnus-xmas.el index 8b5f2d2..36b2b20 100644 --- a/lisp/gnus-xmas.el +++ b/lisp/gnus-xmas.el @@ -50,47 +50,6 @@ automatically." (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. @@ -142,12 +101,12 @@ It is provided only to ease porting of broken FSF Emacs programs." (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 () @@ -292,19 +251,19 @@ call it with the value of the `gnus-data' text property." (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)))))) @@ -429,7 +388,7 @@ call it with the value of the `gnus-data' text property." (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)) @@ -477,6 +436,10 @@ call it with the value of the `gnus-data' text property." (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 @@ -508,8 +471,8 @@ call it with the value of the `gnus-data' text property." `[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]) @@ -671,7 +634,7 @@ If it is non-nil, it must be a toolbar. The five valid values are (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 @@ -686,23 +649,19 @@ XEmacs compatibility workaround." "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") @@ -713,15 +672,13 @@ XEmacs compatibility workaround." (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))) @@ -862,6 +819,31 @@ XEmacs compatibility workaround." (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 diff --git a/lisp/gnus.el b/lisp/gnus.el index 8428a0f..f20cb00 100644 --- a/lisp/gnus.el +++ b/lisp/gnus.el @@ -1,6 +1,6 @@ ;;; 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 ;; Lars Magne Ingebrigtsen @@ -30,6 +30,7 @@ (eval '(run-hooks 'gnus-load-hook)) (eval-when-compile (require 'cl)) +(require 'wid-edit) (require 'mm-util) (defgroup gnus nil @@ -37,6 +38,11 @@ :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") @@ -232,6 +238,11 @@ "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) @@ -256,7 +267,7 @@ is restarted, and sometimes reloaded." :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) @@ -736,13 +747,13 @@ be set in `.emacs' instead." (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 @@ -770,6 +781,38 @@ be set in `.emacs' instead." (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. @@ -779,7 +822,11 @@ be set in `.emacs' instead." (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) @@ -848,19 +895,22 @@ be set in `.emacs' instead." (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) @@ -869,11 +919,11 @@ For example: 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." @@ -888,8 +938,9 @@ REST is a plist of following: (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 @@ -1040,23 +1091,9 @@ see the manual for details." :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) @@ -1072,9 +1109,9 @@ If you want to save your mail in one group and the news articles you 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\". @@ -1122,7 +1159,7 @@ Should be set in paths.el, and shouldn't be touched by the user.") (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) @@ -1161,10 +1198,10 @@ list, Gnus will try all the methods in the list until it finds a match." (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/" @@ -1189,9 +1226,9 @@ If the default site is too slow, try one of these: 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" @@ -1219,7 +1256,8 @@ newsgroups." (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) @@ -1312,11 +1350,6 @@ articles. This is not a good idea." :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. @@ -1374,7 +1407,7 @@ slower." ("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) @@ -1393,7 +1426,8 @@ slower." ("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 @@ -1458,14 +1492,18 @@ to be desirable; see the manual for further details." :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 @@ -1510,15 +1548,15 @@ address was listed in gnus-group-split Addresses (see below).") :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 @@ -1534,12 +1572,12 @@ Use with extreme caution. All groups that match this regexp will be 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.") @@ -1549,7 +1587,7 @@ Use with caution.") :function-document "Return the default charset of GROUP." :variable gnus-group-charset-alist - :variable-default + :variable-default '(("\\(^\\|:\\)hk\\>\\|\\(^\\|:\\)tw\\>\\|\\" cn-big5) ("\\(^\\|:\\)cn\\>\\|\\" cn-gb-2312) ("\\(^\\|:\\)fj\\>\\|\\(^\\|:\\)japan\\>" iso-2022-jp-2) @@ -1564,14 +1602,35 @@ Use with caution.") ("\\(^\\|:\\)\\(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 @@ -1661,6 +1720,18 @@ and `grouplens-menu'." (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) @@ -1747,7 +1818,7 @@ covered by that variable." ,(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) @@ -1755,7 +1826,27 @@ covered by that variable." (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) @@ -1949,7 +2040,8 @@ gnus-newsrc-hashtb should be kept so that both hold the same information.") ("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 @@ -1960,10 +2052,7 @@ gnus-newsrc-hashtb should be kept so that both hold the same information.") 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) @@ -2027,7 +2116,7 @@ gnus-newsrc-hashtb should be kept so that both hold the same information.") 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)))) @@ -2035,7 +2124,7 @@ gnus-newsrc-hashtb should be kept so that both hold the same information.") ;;; 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, @@ -2052,11 +2141,14 @@ with some simple extensions. %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) @@ -2223,18 +2315,6 @@ This restriction may disappear in later versions of Gnus." (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) @@ -2263,6 +2343,19 @@ This restriction may disappear in later versions of Gnus." ;;; 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. @@ -2286,8 +2379,11 @@ If ARG, insert string at point." (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))) @@ -2303,23 +2399,23 @@ If ARG, insert string at point." 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))) @@ -2468,16 +2564,18 @@ that that variable is buffer-local to the summary buffers." (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 () @@ -2648,11 +2746,15 @@ that that variable is buffer-local to the summary buffers." (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))) @@ -2737,28 +2839,83 @@ You should probably use `gnus-find-method-for-group' instead." (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) @@ -2844,7 +3001,7 @@ just the host name." 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))) @@ -3005,7 +3162,7 @@ If NEWSGROUP is nil, return the global kill file name instead." (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) @@ -3055,7 +3212,7 @@ Disallow invalid group names." (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 @@ -3121,8 +3278,8 @@ As opposed to `gnus', this command will not connect to the local server." (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 @@ -3135,6 +3292,9 @@ If ARG is non-nil and a positive number, Gnus will use that as the 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. diff --git a/lisp/hex-util.el b/lisp/hex-util.el new file mode 100644 index 0000000..ddf154d --- /dev/null +++ b/lisp/hex-util.el @@ -0,0 +1,73 @@ +;;; hex-util.el --- Functions to encode/decode hexadecimal string. + +;; Copyright (C) 1999, 2001 Free Software Foundation, Inc. + +;; Author: Shuhei KOBAYASHI +;; 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 diff --git a/lisp/ietf-drums.el b/lisp/ietf-drums.el index b39decb..e1b19a9 100644 --- a/lisp/ietf-drums.el +++ b/lisp/ietf-drums.el @@ -1,5 +1,5 @@ ;;; 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 @@ -199,25 +199,38 @@ (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." diff --git a/lisp/imap.el b/lisp/imap.el index 30838f5..642ff4d 100644 --- a/lisp/imap.el +++ b/lisp/imap.el @@ -1,5 +1,5 @@ ;;; imap.el --- imap library -;; Copyright (C) 1998, 1999, 2000 +;; Copyright (C) 1998, 1999, 2000, 2001 ;; Free Software Foundation, Inc. ;; Author: Simon Josefsson @@ -44,7 +44,7 @@ ;; ;; 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 @@ -57,7 +57,7 @@ ;; 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 @@ -120,7 +120,7 @@ ;; => "X-Sieve: cmu-sieve 1.3^M\nX-Username: ^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 @@ -188,10 +188,10 @@ the list is tried until a successful connection is made." :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 @@ -214,14 +214,38 @@ until a successful connection is made." :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. @@ -240,13 +264,13 @@ until a successful connection is made." (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 @@ -254,7 +278,7 @@ stream.") 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) @@ -263,17 +287,14 @@ stream.") (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. @@ -302,6 +323,8 @@ encoded mailboxes which doesn't translate into ISO-8859-1.") imap-process imap-calculate-literal-size-first imap-mailbox-data)) +(defconst imap-log-buffer "*imap-log*") +(defconst imap-debug-buffer "*imap-debug*") ;; Internal variables. @@ -312,7 +335,7 @@ encoded mailboxes which doesn't translate into ISO-8859-1.") (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'.") @@ -353,7 +376,7 @@ 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 @@ -369,17 +392,26 @@ human readable response text (a string).") "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.") ;; 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) @@ -406,7 +438,7 @@ If ARGS, PROMPT is used as an argument to `format'." (and string (condition-case () (utf7-encode string t) - (error (message + (error (message "imap: Could not UTF7 encode `%s', using it unencoded..." string) string))) @@ -448,7 +480,8 @@ If ARGS, PROMPT is used as an argument to `format'." (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 @@ -462,8 +495,9 @@ If ARGS, PROMPT is used as an argument to `format'." (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) @@ -482,7 +516,7 @@ If ARGS, PROMPT is used as an argument to `format'." (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)) @@ -498,7 +532,7 @@ If ARGS, PROMPT is used as an argument to `format'." (delete-process process) nil))))) done)) - + (defun imap-gssapi-stream-p (buffer) (imap-capability 'AUTH=GSSAPI buffer)) @@ -510,7 +544,8 @@ If ARGS, PROMPT is used as an argument to `format'." (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 @@ -524,8 +559,9 @@ If ARGS, PROMPT is used as an argument to `format'." (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) @@ -541,7 +577,7 @@ If ARGS, PROMPT is used as an argument to `format'." (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)) @@ -565,6 +601,7 @@ If ARGS, PROMPT is used as an argument to `format'." (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)) @@ -582,13 +619,14 @@ If ARGS, PROMPT is used as an argument to `format'." (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)) @@ -600,7 +638,7 @@ If ARGS, PROMPT is used as an argument to `format'." (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) @@ -613,12 +651,13 @@ If ARGS, PROMPT is used as an argument to `format'." (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)) @@ -638,7 +677,7 @@ If ARGS, PROMPT is used as an argument to `format'." (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 @@ -649,12 +688,13 @@ If ARGS, PROMPT is used as an argument to `format'." ?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)) @@ -666,7 +706,7 @@ If ARGS, PROMPT is used as an argument to `format'." (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) @@ -686,12 +726,13 @@ If ARGS, PROMPT is used as an argument to `format'." (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))) @@ -711,7 +752,7 @@ If ARGS, PROMPT is used as an argument to `format'." done) (message "imap: Connecting with STARTTLS...failed") nil))) - + ;; Server functions; authenticator stuff: (defun imap-interactive-login (buffer loginfunc) @@ -720,18 +761,18 @@ 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 '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) @@ -753,7 +794,14 @@ Returns t if login was successful, nil otherwise." 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" @@ -761,7 +809,14 @@ Returns t if login was successful, nil otherwise." (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" @@ -790,8 +845,6 @@ Returns t if login was successful, nil otherwise." (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)) @@ -800,10 +853,10 @@ Returns t if login was successful, nil otherwise." (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) @@ -813,7 +866,7 @@ Returns t if login was successful, nil otherwise." (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) @@ -828,7 +881,7 @@ Returns t if login was successful, nil otherwise." (imap-interactive-login buffer (lambda (user passwd) - (let ((tag + (let ((tag (imap-send-command (list "AUTHENTICATE DIGEST-MD5" @@ -836,10 +889,10 @@ Returns t if login was successful, nil otherwise." (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)))) ))) @@ -858,7 +911,7 @@ Returns t if login was successful, nil otherwise." 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))) @@ -888,7 +941,7 @@ necessery. If nil, the buffer name is generated." (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)) @@ -905,7 +958,7 @@ necessery. If nil, the buffer name is generated." (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 @@ -918,7 +971,7 @@ necessery. If nil, the buffer name is generated." (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) @@ -926,7 +979,7 @@ necessery. If nil, the buffer name is generated." (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))) @@ -958,8 +1011,8 @@ password is remembered in the buffer." (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) @@ -969,9 +1022,8 @@ password is remembered in the 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)) @@ -1029,7 +1081,7 @@ If BUFFER is nil, the current buffer is assumed." (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)) @@ -1065,7 +1117,7 @@ If EXAMINE is non-nil, do a read-only select." 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) @@ -1074,18 +1126,18 @@ If EXAMINE is non-nil, do a read-only select." ;; 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." @@ -1093,7 +1145,7 @@ If EXAMINE is non-nil, do a read-only select." (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 "\""))) @@ -1103,22 +1155,38 @@ If EXAMINE is non-nil, do a read-only select." 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) @@ -1148,7 +1216,7 @@ If BUFFER is nil the current buffer is assumed." (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 @@ -1162,7 +1230,7 @@ implementation-specific string that has to be passed to lsub command." (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)) "%\""))) @@ -1186,7 +1254,7 @@ passed to list command." (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)) "%\""))) @@ -1200,7 +1268,7 @@ passed to list command." "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) "\""))))) @@ -1208,7 +1276,7 @@ Returns non-nil if successful." "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) "\""))))) @@ -1219,13 +1287,13 @@ the STATUS data items -- ie 'messages, 'recent, 'uidnext, 'uidvalidity 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) @@ -1284,8 +1352,8 @@ returned, if ITEMS is a symbol only it's value is returned." (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)) @@ -1305,7 +1373,7 @@ returned, if ITEMS is a symbol only it's value is returned." 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) @@ -1322,7 +1390,7 @@ is non-nil return theese properties." (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 @@ -1396,7 +1464,9 @@ is non-nil return theese properties." (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) @@ -1470,7 +1540,7 @@ first element, rest of list contain the saved articles' UIDs." (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) @@ -1499,11 +1569,11 @@ on failure." (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) @@ -1523,18 +1593,21 @@ on failure." (and from (concat (aref from 0) (if (aref from 0) " <") - (aref from 2) - "@" + (aref from 2) + "@" (aref from 3) (if (aref from 0) ">")))) ;; 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)) @@ -1564,21 +1637,21 @@ on failure." (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)) @@ -1592,7 +1665,7 @@ on failure." (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))) @@ -1604,20 +1677,23 @@ on failure." (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)) @@ -1641,7 +1717,7 @@ Return nil if no complete line has arrived." (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)) @@ -1662,7 +1738,7 @@ Return nil if no complete line has arrived." (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)))))))) @@ -1749,7 +1825,7 @@ Return nil if no complete line has arrived." (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) @@ -1760,21 +1836,21 @@ Return nil if no complete line has arrived." ;; ;; 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 ;; @@ -1809,7 +1885,7 @@ Return nil if no complete line has arrived." (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 @@ -1895,14 +1971,14 @@ Return nil if no complete line has arrived." (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)) @@ -1929,7 +2005,7 @@ Return nil if no complete line has arrived." (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)) @@ -1944,7 +2020,11 @@ Return nil if no complete line has arrived." (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 ;; @@ -1957,14 +2037,14 @@ Return nil if no complete line has arrived." ;; 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*] @@ -1983,7 +2063,7 @@ Return nil if no complete line has arrived." ;; ; 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 @@ -2084,18 +2164,18 @@ Return nil if no complete line has arrived." ;; "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 () @@ -2108,7 +2188,7 @@ Return nil if no complete line has arrived." (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 @@ -2118,8 +2198,8 @@ Return nil if no complete line has arrived." (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)))) @@ -2127,7 +2207,9 @@ Return nil if no complete line has arrived." (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) @@ -2156,7 +2238,7 @@ Return nil if no complete line has arrived." (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)) @@ -2170,7 +2252,7 @@ Return nil if no complete line has arrived." ;; mailbox-data = ... ;; "STATUS" SP mailbox SP "(" -;; [status-att SP number +;; [status-att SP number ;; *(SP status-att SP number)] ")" ;; ... ;; @@ -2195,7 +2277,7 @@ Return nil if no complete line has arrived." ((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 @@ -2234,12 +2316,16 @@ Return nil if no complete line has arrived." (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))) @@ -2270,31 +2356,31 @@ Return nil if no complete line has arrived." (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)) @@ -2324,7 +2410,7 @@ Return nil if no complete line has arrived." (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) @@ -2342,7 +2428,7 @@ Return nil if no complete line has arrived." (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) ?\() @@ -2352,14 +2438,14 @@ Return nil if no complete line has arrived." (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)) @@ -2433,89 +2519,89 @@ Return nil if no complete line has arrived." (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 @@ -2609,7 +2695,7 @@ Return nil if no complete line has arrived." imap-parse-body-extension imap-parse-body ))) - + (provide 'imap) ;;; imap.el ends here diff --git a/lisp/lpath.el b/lisp/lpath.el index 867de91..3879b1f 100644 --- a/lisp/lpath.el +++ b/lisp/lpath.el @@ -13,15 +13,25 @@ (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 @@ -33,12 +43,19 @@ (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) @@ -57,13 +74,15 @@ 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 @@ -79,7 +98,7 @@ 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 @@ -93,7 +112,8 @@ 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) diff --git a/lisp/mail-parse.el b/lisp/mail-parse.el index 95a3359..a5de09b 100644 --- a/lisp/mail-parse.el +++ b/lisp/mail-parse.el @@ -59,7 +59,11 @@ (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) diff --git a/lisp/mail-source.el b/lisp/mail-source.el index 618d02e..982db42 100644 --- a/lisp/mail-source.el +++ b/lisp/mail-source.el @@ -36,6 +36,7 @@ (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." @@ -223,12 +224,17 @@ If non-nil, this maildrop will be checked periodically for new mail." :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) @@ -258,6 +264,11 @@ If non-nil, this maildrop will be checked periodically for new mail." :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 "" @@ -444,13 +455,15 @@ Return the number of files that were found." (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)) @@ -517,11 +530,13 @@ Pass INFO on to CALLBACK." '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 @@ -662,15 +677,17 @@ If ARGS, PROMPT is used as an argument to `format'." (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) @@ -721,15 +738,17 @@ If ARGS, PROMPT is used as an argument to `format'." (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)) @@ -742,6 +761,10 @@ If ARGS, PROMPT is used as an argument to `format'." (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) @@ -764,8 +787,9 @@ If ARGS, PROMPT is used as an argument to `format'." 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 @@ -778,7 +802,7 @@ If ARGS, PROMPT is used as an argument to `format'." 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)))) @@ -889,7 +913,11 @@ This only works when `display-time' is enabled." (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 @@ -905,7 +933,7 @@ This only works when `display-time' is enabled." 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 diff --git a/lisp/mailcap.el b/lisp/mailcap.el index bcfd238..52e5c9a 100644 --- a/lisp/mailcap.el +++ b/lisp/mailcap.el @@ -282,11 +282,15 @@ to return a true or false shell value for the validity.") (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 ;;; @@ -314,7 +318,7 @@ If you are unsure what to do, please answer \"no\"." "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))) @@ -363,7 +367,7 @@ MAILCAPS if set; otherwise (on Unix) use the path from RFC 1524, plus (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 @@ -730,9 +734,8 @@ this type is returned." ((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 @@ -860,7 +863,7 @@ If FORCE, re-parse even if already parsed." (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 diff --git a/lisp/message.el b/lisp/message.el index d0ac833..346461c 100644 --- a/lisp/message.el +++ b/lisp/message.el @@ -1,4 +1,4 @@ -;;; 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. @@ -32,7 +32,8 @@ (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: @@ -40,6 +41,9 @@ (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)) @@ -169,7 +173,7 @@ Checks include `subject-cmsg', `multiple-headers', `sendsys', `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 @@ -190,7 +194,7 @@ header, remove it from this list." '(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 @@ -215,7 +219,7 @@ included. Organization, Lines and User-Agent are optional." :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." @@ -339,7 +343,7 @@ The provided functions are: (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." @@ -409,9 +413,63 @@ 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 :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." @@ -511,14 +569,27 @@ the signature is inserted." ;;;###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) @@ -714,8 +785,8 @@ If nil, you might be asked to input the charset." (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) @@ -747,10 +818,6 @@ candidates: 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)) @@ -979,6 +1046,21 @@ Except if it is nil, use Gnus native MUA; if it is t, use :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...") @@ -1081,6 +1163,12 @@ Except if it is nil, use Gnus native MUA; if it is t, use (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") @@ -1097,6 +1185,8 @@ Except if it is nil, use Gnus native MUA; if it is t, use (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")) @@ -1117,11 +1207,11 @@ Except if it is nil, use Gnus native MUA; if it is t, use (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. @@ -1156,7 +1246,7 @@ is used by default." ((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." @@ -1240,7 +1330,7 @@ is used by default." 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)) @@ -1429,8 +1519,10 @@ Point is left at the beginning of the narrowed-to region." (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) @@ -1450,6 +1542,7 @@ Point is left at the beginning of the narrowed-to region." (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) @@ -1458,58 +1551,66 @@ Point is left at the beginning of the narrowed-to 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) @@ -1517,8 +1618,63 @@ Point is left at the beginning of the narrowed-to region." (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:\\ C-c C-s `message-send' (send the message) C-c C-c `message-send-and-exit' @@ -1530,6 +1686,7 @@ C-c C-f move to a header field (and create it if there isn't): 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). @@ -1542,36 +1699,24 @@ C-c C-v `message-delete-not-region' (remove the text outside the region). 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) @@ -1589,6 +1734,12 @@ M-RET `message-newline-and-reformat' (break the line and reformat)." (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) @@ -1596,14 +1747,12 @@ M-RET `message-newline-and-reformat' (break the line and reformat)." (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) @@ -1611,27 +1760,37 @@ M-RET `message-newline-and-reformat' (break the line and reformat)." (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 Date: 2001-10-19. + (when auto-fill-function + (setq auto-fill-function normal-auto-fill-function))) @@ -1686,6 +1845,11 @@ M-RET `message-newline-and-reformat' (break the line and reformat)." (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) @@ -1704,7 +1868,7 @@ M-RET `message-newline-and-reformat' (break the line and reformat)." (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." @@ -1779,17 +1943,25 @@ With the prefix argument FORCE, insert the header anyway." (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))) @@ -1817,7 +1989,7 @@ Prefix arg means justify as well." (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) @@ -1880,7 +2052,7 @@ Prefix arg means justify as well." (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)) @@ -1890,8 +2062,25 @@ Prefix arg means justify as well." (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'." @@ -1930,6 +2119,42 @@ Prefix arg means justify as well." (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 @@ -1950,7 +2175,7 @@ text was killed." (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) @@ -1993,7 +2218,7 @@ Mail and USENET news headers are not rotated." (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)))) @@ -2073,8 +2298,10 @@ However, if `message-yank-prefix' is non-nil, insert that prefix on each line." (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) @@ -2150,7 +2377,7 @@ prefix, and don't delete any headers." (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) @@ -2262,9 +2489,23 @@ The text will also be indented the normal way." (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) @@ -2295,7 +2536,7 @@ It should typically alter the sending method in some way or other." (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 @@ -2309,12 +2550,25 @@ It should typically alter the sending method in some way or other." (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)) @@ -2432,22 +2686,21 @@ It should typically alter the sending method in some way or other." (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))) @@ -2463,13 +2716,27 @@ It should typically alter the sending method in some way or other." (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 @@ -2513,7 +2780,8 @@ It should typically alter the sending method in some way or other." (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) @@ -2621,7 +2889,7 @@ to find out how to use this." ;; 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")))) @@ -2644,29 +2912,63 @@ to find out how to use this." ;; 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 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 @@ -2674,14 +2976,19 @@ to find out how to use this." (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 @@ -2857,17 +3164,36 @@ to find out how to use this." (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 , 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. @@ -2891,69 +3217,103 @@ to find out how to use this." (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 @@ -2964,7 +3324,7 @@ to find out how to use this." (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) @@ -3049,8 +3409,8 @@ to find out how to use this." (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)) @@ -3060,47 +3420,49 @@ to find out how to use this." (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." @@ -3132,7 +3494,7 @@ to find out how to use this." (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)) @@ -3151,6 +3513,9 @@ If NOW, use that time instead." (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 " @@ -3375,7 +3740,8 @@ give as trustworthy answer as possible." (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'. @@ -3403,6 +3769,45 @@ give as trustworthy answer as possible." (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." @@ -3612,12 +4017,12 @@ 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) @@ -3683,6 +4088,19 @@ than 988 characters long, and if they are not, trim them until they are." (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 @@ -3736,7 +4154,7 @@ than 988 characters long, and if they are not, trim them until they are." ;; 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))) @@ -3746,17 +4164,22 @@ than 988 characters long, and if they are not, trim them until they are." ;; 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) "*")) @@ -3804,15 +4227,11 @@ than 988 characters long, and if they are not, trim them until they are." 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. @@ -3877,7 +4296,10 @@ than 988 characters long, and if they are not, trim them until they are." (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)) @@ -3932,7 +4354,7 @@ OTHER-HEADERS is an alist of header/value pairs." (nconc `((To . ,(or to "")) (Subject . ,(or subject ""))) (when other-headers other-headers)) - replybuffer) + replybuffer send-actions) ;; FIXME: Should return nil if failure. t)) @@ -3946,16 +4368,17 @@ OTHER-HEADERS is an alist of header/value pairs." (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 @@ -3965,75 +4388,82 @@ OTHER-HEADERS is an alist of header/value pairs." (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 ") ...). + (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." @@ -4063,16 +4493,16 @@ responses here are directed to other addresses."))) 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 @@ -4185,7 +4615,7 @@ used to direct the following discussion to one newsgroup only, 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)))))) @@ -4229,15 +4659,31 @@ If ARG, allow editing of the cancellation message." 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 + ;; + ;; + ;; 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. @@ -4273,7 +4719,23 @@ header line with the old Message-ID." (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 + ;; + ;; + ;; 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) @@ -4326,7 +4788,7 @@ header line with the old Message-ID." "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 @@ -4364,13 +4826,13 @@ The form is: [Source] Subject, where if the original message was mail, 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) @@ -4409,6 +4871,7 @@ the message." (eval-when-compile (defvar gnus-article-decoded-p)) + ;;;###autoload (defun message-forward (&optional news digest) "Forward the current message via mail. @@ -4416,39 +4879,42 @@ Optional NEWS will use news to forward instead of 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) @@ -4456,37 +4922,53 @@ Optional DIGEST will use digest to forward." (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) @@ -4558,15 +5040,17 @@ you." (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 @@ -4698,25 +5182,52 @@ which specify the range to operate on." (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." @@ -4760,6 +5271,11 @@ Do a `tab-to-tab-stop' if not in those headers." (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) @@ -4868,9 +5384,10 @@ regexp varstr." ;; /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." @@ -4922,10 +5439,15 @@ regexp varstr." (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) diff --git a/lisp/messagexmas.el b/lisp/messagexmas.el index 65baf83..bc02b00 100644 --- a/lisp/messagexmas.el +++ b/lisp/messagexmas.el @@ -118,7 +118,7 @@ If it is non-nil, it must be a toolbar. The five valid values are (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) diff --git a/lisp/mm-bodies.el b/lisp/mm-bodies.el index 28d202e..19cd5a4 100644 --- a/lisp/mm-bodies.el +++ b/lisp/mm-bodies.el @@ -1,5 +1,7 @@ ;;; 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 ;; MORIOKA Tomohiko @@ -70,7 +72,7 @@ If no encoding was done, nil is returned." (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 @@ -82,7 +84,8 @@ If no encoding was done, nil is returned." (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. @@ -128,6 +131,8 @@ If no encoding was done, nil is returned." (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) @@ -180,11 +185,14 @@ If no encoding was done, nil is returned." ;;; (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) @@ -203,18 +211,21 @@ If no encoding was done, nil is returned." (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 @@ -232,7 +243,7 @@ If no encoding was done, nil is returned." 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)) @@ -245,7 +256,7 @@ The characters in CHARSET should then be decoded." (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 @@ -261,7 +272,7 @@ The characters in CHARSET should then be decoded." "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)) @@ -272,7 +283,7 @@ The characters in CHARSET should then be decoded." (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) @@ -283,4 +294,4 @@ The characters in CHARSET should then be decoded." (provide 'mm-bodies) -;; mm-bodies.el ends here +;;; mm-bodies.el ends here diff --git a/lisp/mm-decode.el b/lisp/mm-decode.el index d09669b..54f61ec 100644 --- a/lisp/mm-decode.el +++ b/lisp/mm-decode.el @@ -22,18 +22,29 @@ ;;; 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") @@ -140,6 +151,7 @@ (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) @@ -166,9 +178,16 @@ ("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") @@ -179,22 +198,38 @@ '("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) @@ -235,10 +270,38 @@ to: :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. @@ -246,6 +309,7 @@ If not set, `default-directory' will be used." (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 @@ -332,6 +396,31 @@ The original alist is not modified. See also `destructive-alist-to-plist'." (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 @@ -375,30 +464,33 @@ The original alist is not modified. See also `destructive-alist-to-plist'." (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))) @@ -480,7 +572,8 @@ external if displayed external." (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) @@ -529,9 +622,13 @@ external if displayed external." (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) @@ -548,53 +645,76 @@ external if displayed external." (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)) @@ -611,16 +731,18 @@ external if displayed external." (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) @@ -674,7 +796,7 @@ external if displayed external." ((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))))) @@ -691,6 +813,18 @@ external if displayed external." (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) @@ -704,28 +838,14 @@ external if displayed external." (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)) @@ -793,21 +913,52 @@ external if displayed external." (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." @@ -816,7 +967,8 @@ external if displayed external." (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 @@ -849,7 +1001,8 @@ external if displayed external." (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." @@ -902,6 +1055,35 @@ external if displayed external." "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)) @@ -922,31 +1104,40 @@ external if displayed external." (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))) @@ -1051,10 +1242,22 @@ If RECURSIVE, search recursively." (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)) @@ -1123,18 +1326,27 @@ If RECURSIVE, search recursively." 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 diff --git a/lisp/mm-encode.el b/lisp/mm-encode.el index 677c2df..04a067f 100644 --- a/lisp/mm-encode.el +++ b/lisp/mm-encode.el @@ -1,4 +1,4 @@ -;;; 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 @@ -36,7 +36,7 @@ ("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.") @@ -106,7 +106,7 @@ This variable should never be set directly, but bound before a call to ((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. @@ -119,7 +119,8 @@ The encoding used is returned." (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)) @@ -144,7 +145,7 @@ The encoding used is returned." (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))))) diff --git a/lisp/mm-extern.el b/lisp/mm-extern.el index ec5c9b1..dfad89f 100644 --- a/lisp/mm-extern.el +++ b/lisp/mm-extern.el @@ -25,11 +25,11 @@ ;;; 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) @@ -48,22 +48,21 @@ (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))) @@ -79,7 +78,7 @@ "@" 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))) @@ -119,13 +118,13 @@ If NO-DISPLAY is nil, display it. Otherwise, do nothing after replacing." (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)) @@ -133,7 +132,7 @@ If NO-DISPLAY is nil, display it. Otherwise, do nothing after replacing." (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) @@ -164,4 +163,6 @@ If NO-DISPLAY is nil, display it. Otherwise, do nothing after replacing." (error nil)) (delete-region ,(point-min-marker) ,(point-max-marker)))))))))) -;; mm-extern.el ends here +(provide 'mm-extern) + +;;; mm-extern.el ends here diff --git a/lisp/mm-partial.el b/lisp/mm-partial.el index d05283c..216340c 100644 --- a/lisp/mm-partial.el +++ b/lisp/mm-partial.el @@ -25,8 +25,7 @@ ;;; Code: -(eval-when-compile - (require 'cl)) +(eval-when-compile (require 'cl)) (require 'gnus-sum) (require 'mm-util) @@ -66,7 +65,7 @@ If NO-DISPLAY is nil, display it. Otherwise, do nothing after replacing." 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 @@ -96,7 +95,7 @@ If NO-DISPLAY is nil, display it. Otherwise, do nothing after replacing." (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) @@ -149,4 +148,6 @@ If NO-DISPLAY is nil, display it. Otherwise, do nothing after replacing." (error nil)) (delete-region ,(point-min-marker) ,(point-max-marker)))))))))) -;; mm-partial.el ends here +(provide 'mm-partial) + +;;; mm-partial.el ends here diff --git a/lisp/mm-url.el b/lisp/mm-url.el new file mode 100644 index 0000000..89072f7 --- /dev/null +++ b/lisp/mm-url.el @@ -0,0 +1,379 @@ +;;; mm-url.el --- a wrapper of url functions/commands for Gnus +;; Copyright (C) 2001 Free Software Foundation, Inc. + +;; Author: Shenghuo Zhu + +;; 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 + "]*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) + (point-max)))) + (goto-char (point-min)) + (while (re-search-forward "<[^>]+>" nil t) + (replace-match "" t t))) + +(provide 'mm-url) + +;;; mm-url.el ends here diff --git a/lisp/mm-util.el b/lisp/mm-util.el index d0ff546..f597cb2 100644 --- a/lisp/mm-util.el +++ b/lisp/mm-util.el @@ -27,59 +27,6 @@ (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) @@ -100,12 +47,6 @@ (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." @@ -118,7 +59,7 @@ (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. @@ -128,6 +69,7 @@ (setq idx (1+ idx))) string))) (string-as-unibyte . identity) + (string-as-multibyte . identity) (multibyte-string-p . ignore)))) (eval-and-compile @@ -137,6 +79,21 @@ ((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." @@ -149,14 +106,32 @@ (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 @@ -187,20 +162,146 @@ (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. @@ -209,12 +310,11 @@ If optional argument LBT (`unix', `dos' or `mac') is specified, it is 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) @@ -223,57 +323,78 @@ used as the line break code type of the coding system." '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. @@ -296,10 +417,10 @@ If the charset is `composition', return the actual one." (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 @@ -310,9 +431,9 @@ If the charset is `composition', return the actual one." 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 @@ -335,21 +456,8 @@ If the charset is `composition', return the actual one." (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)) @@ -357,6 +465,72 @@ If the charset is `composition', return the actual one." 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." @@ -369,18 +543,17 @@ 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) @@ -389,20 +562,17 @@ Equivalent to `progn' in XEmacs" (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) @@ -419,12 +589,13 @@ Mule4 only." "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. @@ -489,7 +660,7 @@ If INHIBIT is non-nil, inhibit mm-inhibit-file-name-handlers. (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 diff --git a/lisp/mm-uu.el b/lisp/mm-uu.el index 5f93e7b..f36a5fd 100644 --- a/lisp/mm-uu.el +++ b/lisp/mm-uu.el @@ -1,4 +1,4 @@ -;;; 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 @@ -23,7 +23,6 @@ ;;; Commentary: - ;;; Code: (eval-when-compile (require 'cl)) @@ -32,20 +31,23 @@ (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) @@ -54,8 +56,9 @@ decoder, such as uudecode." 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 @@ -372,7 +375,7 @@ Return that buffer." (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) @@ -403,7 +406,7 @@ Return that buffer." (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 diff --git a/lisp/mm-view.el b/lisp/mm-view.el index 976cdff..840ad4c 100644 --- a/lisp/mm-view.el +++ b/lisp/mm-view.el @@ -1,4 +1,4 @@ -;;; 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 @@ -34,11 +34,13 @@ (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) @@ -49,10 +51,11 @@ `(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 () @@ -87,6 +90,8 @@ (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)) @@ -103,11 +108,14 @@ (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 @@ -116,10 +124,24 @@ ;; 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 @@ -134,24 +156,16 @@ '(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 @@ -176,6 +190,9 @@ (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 () @@ -202,7 +219,9 @@ (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 () @@ -303,6 +322,58 @@ (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 diff --git a/lisp/mml-sec.el b/lisp/mml-sec.el index cc54995..3d30602 100644 --- a/lisp/mml-sec.el +++ b/lisp/mml-sec.el @@ -23,13 +23,14 @@ ;;; 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.") @@ -38,6 +39,7 @@ (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.") @@ -54,6 +56,14 @@ (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"))) @@ -78,14 +88,19 @@ (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." @@ -97,6 +112,11 @@ (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) diff --git a/lisp/mml-smime.el b/lisp/mml-smime.el index 46db906..ac87492 100644 --- a/lisp/mml-smime.el +++ b/lisp/mml-smime.el @@ -32,7 +32,8 @@ (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) @@ -56,7 +57,8 @@ 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 @@ -146,8 +148,8 @@ 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)) @@ -168,10 +170,10 @@ (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 ", ")) diff --git a/lisp/mml.el b/lisp/mml.el index 4622a4d..2fabf3e 100644 --- a/lisp/mml.el +++ b/lisp/mml.el @@ -37,6 +37,33 @@ (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 @@ -121,18 +148,25 @@ one charsets.") (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"))) @@ -148,14 +182,11 @@ Message contains characters with unknown encoding. Really send?") 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) @@ -249,7 +280,7 @@ A message part needs to be split into %d charset parts. Really send? " "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 @@ -295,6 +326,7 @@ If MML is non-nil, return the buffer up till the correspondent mml tag." (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))) @@ -302,49 +334,53 @@ If MML is non-nil, return the buffer up till the correspondent mml tag." (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)) @@ -356,10 +392,11 @@ If MML is non-nil, return the buffer up till the correspondent mml tag." (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 @@ -480,7 +517,7 @@ If MML is non-nil, return the buffer up till the correspondent mml tag." (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))) @@ -493,17 +530,17 @@ If MML is non-nil, return the buffer up till the correspondent mml tag." "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))) @@ -581,6 +618,7 @@ If HANDLES is non-nil, use it instead reparsing the buffer." ;; 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 () @@ -668,8 +706,10 @@ If HANDLES is non-nil, use it instead reparsing the buffer." (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) @@ -688,32 +728,33 @@ If HANDLES is non-nil, use it instead reparsing the 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") @@ -731,7 +772,7 @@ If HANDLES is non-nil, use it instead reparsing the buffer." (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)) @@ -861,13 +902,14 @@ TYPE is the MIME type to use." "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 " @@ -877,7 +919,8 @@ If RAW, don't highlight the article." (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))) @@ -889,7 +932,7 @@ If RAW, don't highlight the article." (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))) @@ -900,6 +943,27 @@ If RAW, don't highlight the article." (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 diff --git a/lisp/mml1991.el b/lisp/mml1991.el new file mode 100644 index 0000000..d91fb05 --- /dev/null +++ b/lisp/mml1991.el @@ -0,0 +1,217 @@ +;;; 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 , +;; Simon Josefsson (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 diff --git a/lisp/mml2015.el b/lisp/mml2015.el index 4f83483..5c88821 100644 --- a/lisp/mml2015.el +++ b/lisp/mml2015.el @@ -23,6 +23,9 @@ ;;; Commentary: +;; RFC 2015 is updated by RFC 3156, this file should be compatible +;; with both. + ;;; Code: (eval-when-compile (require 'cl)) @@ -60,6 +63,18 @@ (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 @@ -77,6 +92,11 @@ (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) @@ -93,7 +113,7 @@ (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 @@ -118,7 +138,7 @@ (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 @@ -132,7 +152,8 @@ (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)))) @@ -175,38 +196,68 @@ (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) @@ -216,14 +267,14 @@ 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" @@ -234,12 +285,12 @@ (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 @@ -273,7 +324,7 @@ (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" @@ -314,7 +365,10 @@ (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)) @@ -334,15 +388,54 @@ (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) @@ -354,6 +447,16 @@ (with-temp-buffer (setq message (current-buffer)) (insert part) + ;; Convert to 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 @@ -371,19 +474,26 @@ (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 () @@ -396,16 +506,16 @@ (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"))) @@ -424,7 +534,7 @@ 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)) @@ -464,7 +574,7 @@ 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)) @@ -530,7 +640,7 @@ (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) @@ -538,7 +648,7 @@ (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 () diff --git a/lisp/nnagent.el b/lisp/nnagent.el index 50777ac..6a3b7be 100644 --- a/lisp/nnagent.el +++ b/lisp/nnagent.el @@ -1,5 +1,7 @@ ;;; 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 ;; Keywords: news, mail @@ -67,7 +69,7 @@ (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)) @@ -121,68 +123,68 @@ (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 diff --git a/lisp/nnbabyl.el b/lisp/nnbabyl.el index 8389e17..b9acfe6 100644 --- a/lisp/nnbabyl.el +++ b/lisp/nnbabyl.el @@ -1,6 +1,6 @@ ;;; 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 @@ -51,6 +51,7 @@ (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.") @@ -282,12 +283,13 @@ (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)) diff --git a/lisp/nndb.el b/lisp/nndb.el index 23cc556..6cc95c3 100644 --- a/lisp/nndb.el +++ b/lisp/nndb.el @@ -175,7 +175,7 @@ article was posted to nndb") (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)) @@ -202,12 +202,12 @@ article was posted to nndb") (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 @@ -219,15 +219,15 @@ article was posted to nndb") ;; 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 @@ -268,19 +268,19 @@ Optional LAST is ignored." (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) @@ -307,11 +307,11 @@ Optional LAST is ignored." (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 @@ -326,3 +326,5 @@ Optional LAST is ignored." (nntp)) (provide 'nndb) + +;;; nndb.el ends here diff --git a/lisp/nndiary.el b/lisp/nndiary.el new file mode 100644 index 0000000..45aac6c --- /dev/null +++ b/lisp/nndiary.el @@ -0,0 +1,1715 @@ +;;; nndiary.el --- A diary backend for Gnus + +;; Copyright (C) 1999, 2000, 2001 +;; Free Software Foundation, Inc. + +;; Author: Didier Verna +;; Maintainer: Didier Verna +;; 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-', the 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 +;; (even in strings) with , 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.") + + + +(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)))) + + +;;; 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)) + + + +;;; 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 diff --git a/lisp/nndoc.el b/lisp/nndoc.el index a9824fe..0f73e10 100644 --- a/lisp/nndoc.el +++ b/lisp/nndoc.el @@ -1,5 +1,5 @@ ;;; 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 @@ -25,6 +25,8 @@ ;;; Commentary: +;; For Outlook mail boxes format, see http://mbx2mbox.sourceforge.net/ + ;;; Code: (require 'nnheader) @@ -41,7 +43,8 @@ "*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'.") @@ -70,14 +73,14 @@ from the document.") (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^ \\*") @@ -128,6 +131,14 @@ from the document.") (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)) @@ -138,6 +149,9 @@ from the document.") (guess . t) (subtype nil)))) +(defvar nndoc-binary-file-names ".[Dd][Bb][Xx]$" + "Regexp for binary nndoc file names.") + (defvoo nndoc-file-begin nil) (defvoo nndoc-first-article nil) @@ -163,6 +177,8 @@ from the document.") (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) @@ -213,8 +229,11 @@ from the document.") (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") @@ -226,7 +245,7 @@ from the document.") (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." @@ -246,8 +265,8 @@ from the document.") (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) @@ -299,10 +318,14 @@ from the document.") (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)) @@ -331,7 +354,9 @@ from the document.") 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) @@ -436,11 +461,9 @@ from the document.") 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 () @@ -450,6 +473,10 @@ from the document.") (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) @@ -600,10 +627,75 @@ from the document.") ;; 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 ;;; @@ -625,43 +717,45 @@ from the document.") ;; 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 diff --git a/lisp/nndraft.el b/lisp/nndraft.el index 1214406..0820b34 100644 --- a/lisp/nndraft.el +++ b/lisp/nndraft.el @@ -1,5 +1,6 @@ ;;; 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 @@ -32,8 +33,7 @@ (require 'nnmh) (require 'nnoo) (require 'mm-util) -(eval-when-compile - (require 'cl)) +(eval-when-compile (require 'cl)) (nnoo-declare nndraft nnmh) @@ -132,7 +132,9 @@ (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) @@ -180,8 +182,7 @@ (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))) diff --git a/lisp/nneething.el b/lisp/nneething.el index 1d83717..0d9d760 100644 --- a/lisp/nneething.el +++ b/lisp/nneething.el @@ -122,11 +122,11 @@ included.") (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 @@ -234,7 +234,7 @@ included.") 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)))) @@ -352,7 +352,7 @@ included.") (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)) @@ -365,7 +365,7 @@ included.") (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) diff --git a/lisp/nnfolder.el b/lisp/nnfolder.el index 95b9142..25613f6 100644 --- a/lisp/nnfolder.el +++ b/lisp/nnfolder.el @@ -1,8 +1,9 @@ ;;; 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 (adding NOV) +;; Author: Simon Josefsson (adding MARKS) +;; ShengHuo Zhu (adding NOV) ;; Scott Byer ;; Lars Magne Ingebrigtsen ;; Masanobu UMEDA @@ -34,10 +35,12 @@ (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) @@ -49,6 +52,10 @@ "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.") @@ -84,6 +91,7 @@ message, a huge time saver for large mailboxes.") (defvoo nnfolder-save-buffer-hook nil "Hook run before saving the nnfolder mbox buffer.") + (defvoo nnfolder-inhibit-expiry nil "If non-nil, inhibit expiry.") @@ -103,12 +111,12 @@ message, a huge time saver for large mailboxes.") (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. @@ -125,6 +133,21 @@ all. This may very well take some time.") (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)) + ;;; Interface functions @@ -144,7 +167,7 @@ all. This may very well take some time.") '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))) @@ -171,6 +194,9 @@ all. This may very well take some time.") (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) @@ -220,7 +246,7 @@ all. This may very well take some time.") (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 @@ -349,7 +375,7 @@ all. This may very well take some time.") (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 @@ -383,11 +409,12 @@ all. This may very well take some time.") 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) @@ -417,7 +444,7 @@ all. This may very well take some time.") (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)))) @@ -447,33 +474,35 @@ all. This may very well take some time.") (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")) @@ -503,7 +532,7 @@ all. This may very well take some time.") (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) @@ -520,7 +549,10 @@ all. This may very well take some time.") ;; 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) @@ -539,9 +571,14 @@ all. This may very well take some time.") (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))) @@ -636,30 +673,26 @@ deleted. Point is left where the deleted region was." (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) @@ -675,7 +708,7 @@ deleted. Point is left where the deleted region was." ;; 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))) @@ -741,7 +774,8 @@ deleted. Point is left where the deleted region was." (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 @@ -777,28 +811,30 @@ deleted. Point is left where the deleted region was." (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. @@ -842,12 +878,12 @@ deleted. Point is left where the deleted region was." (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)) @@ -868,16 +904,17 @@ deleted. Point is left where the deleted region was." (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)) @@ -887,16 +924,16 @@ deleted. Point is left where the deleted region was." ;; (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)) @@ -908,26 +945,27 @@ deleted. Point is left where the deleted region was." (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 @@ -941,32 +979,32 @@ This command does not work if you use short group names." (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) @@ -992,7 +1030,7 @@ This command does not work if you use short group names." (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))) @@ -1024,7 +1062,7 @@ This command does not work if you use short group names." (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)) @@ -1061,29 +1099,29 @@ This command does not work if you use short group names." "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." @@ -1093,6 +1131,110 @@ This command does not work if you use short group names." (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 diff --git a/lisp/nngateway.el b/lisp/nngateway.el index 65bd2cc..6059dcf 100644 --- a/lisp/nngateway.el +++ b/lisp/nngateway.el @@ -1,6 +1,6 @@ ;;; 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 @@ -65,7 +65,8 @@ parameter -- the gateway address.") (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 diff --git a/lisp/nnheader.el b/lisp/nnheader.el index b15885e..bbcc672 100644 --- a/lisp/nnheader.el +++ b/lisp/nnheader.el @@ -33,7 +33,7 @@ ;; 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) @@ -42,8 +42,29 @@ (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.") @@ -60,7 +81,6 @@ on your system, you could say something like: (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. @@ -176,13 +196,14 @@ on your system, you could say something like: (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) @@ -219,18 +240,17 @@ on your system, you could say something like: ;; 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 @@ -246,12 +266,12 @@ on your system, you could say something like: ;; 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) @@ -263,7 +283,7 @@ on your system, you could say something like: (match-end 0))) (when (> (length ref2) (length ref)) (setq ref ref2))) - ref) + ref) nil))) ;; Chars. 0 @@ -277,7 +297,7 @@ on your system, you could say something like: ;; Xref. (progn (goto-char p) - (and (search-forward "\nxref: " nil t) + (and (search-forward "\nxref:" nil t) (nnheader-header-value))) ;; Extra. @@ -287,7 +307,7 @@ on your system, you could say something like: (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)) @@ -430,7 +450,8 @@ the line could be found." (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) @@ -461,10 +482,7 @@ the line could be found." ;; 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) @@ -475,11 +493,12 @@ the line could be found." (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. @@ -599,7 +618,10 @@ the line could be found." (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, @@ -616,7 +638,7 @@ 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 @@ -625,7 +647,7 @@ an alarming frequency on NFS mounted file systems. If it is nil, (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 @@ -652,12 +674,12 @@ If FULL, translate everything." ;; 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" @@ -766,7 +788,7 @@ without formatting." ;; 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)) @@ -842,7 +864,7 @@ find-file-hooks, etc. (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)) diff --git a/lisp/nnheaderxm.el b/lisp/nnheaderxm.el index 174d76c..972067b 100644 --- a/lisp/nnheaderxm.el +++ b/lisp/nnheaderxm.el @@ -1,6 +1,6 @@ ;;; 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 @@ -41,4 +41,4 @@ (provide 'nnheaderxm) -;;; nnheaderxm.el ends here. +;;; nnheaderxm.el ends here diff --git a/lisp/nnimap.el b/lisp/nnimap.el index dddb85d..a5bd4d4 100644 --- a/lisp/nnimap.el +++ b/lisp/nnimap.el @@ -58,10 +58,7 @@ ;;; Code: -(eval-and-compile - (require 'cl) - (require 'imap)) - +(require 'imap) (require 'nnoo) (require 'nnmail) (require 'nnheader) @@ -73,7 +70,11 @@ (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.") @@ -84,20 +85,36 @@ If nil, defaults to 993 for SSL connections and 143 otherwise.") ;; 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'. @@ -106,7 +123,7 @@ If you'd like, for instance, one mail group for mail from the 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 @@ -127,29 +144,63 @@ 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: -(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 @@ -237,7 +288,8 @@ There are two wildcards * and %. * matches everything, % matches 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. @@ -252,6 +304,22 @@ news-like mailboxes. If you wish to have a group with todo items or 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'.") @@ -298,8 +366,8 @@ For example: (setq nnimap-debug \"*nnimap-debug*\")") (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 @@ -325,13 +393,13 @@ If SERVER is nil, uses the current server." (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 @@ -369,7 +437,7 @@ If EXAMINE is non-nil the group is selected read-only." 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) @@ -380,12 +448,14 @@ If EXAMINE is non-nil the group is selected read-only." (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) @@ -459,38 +529,38 @@ If EXAMINE is non-nil the group is selected read-only." (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) @@ -571,11 +641,11 @@ If EXAMINE is non-nil the group is selected read-only." (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)) @@ -598,9 +668,9 @@ If EXAMINE is non-nil the group is selected read-only." (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) @@ -626,6 +696,8 @@ If EXAMINE is non-nil the group is selected read-only." (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 @@ -683,16 +755,16 @@ function is generally only called when Gnus is shutting down." (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 @@ -704,12 +776,12 @@ function is generally only called when Gnus is shutting down." (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) @@ -771,14 +843,14 @@ function is generally only called when Gnus is shutting down." (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)))) @@ -806,9 +878,9 @@ function is generally only called when Gnus is shutting down." (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)) @@ -816,8 +888,8 @@ function is generally only called when Gnus is shutting down." (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) @@ -845,6 +917,10 @@ function is generally only called when Gnus is shutting down." (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)))))))) @@ -853,11 +929,11 @@ function is generally only called when Gnus is shutting down." (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 @@ -881,12 +957,13 @@ function is generally only called when Gnus is shutting down." (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)))) @@ -894,18 +971,19 @@ function is generally only called when Gnus is shutting down." 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)) @@ -926,11 +1004,22 @@ function is generally only called when Gnus is shutting down." (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 @@ -979,7 +1068,7 @@ function is generally only called when Gnus is shutting down." (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) @@ -987,7 +1076,7 @@ function is generally only called when Gnus is shutting down." to-groups) (or nnimap-split-crosspost (throw 'split-done to-groups)))))))))) - + (defun nnimap-assoc-match (key alist) (let (element) (while (and alist (not element)) @@ -998,9 +1087,9 @@ function is generally only called when Gnus is shutting down." (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)) @@ -1015,7 +1104,7 @@ function is generally only called when Gnus is shutting down." (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 @@ -1024,21 +1113,25 @@ function is generally only called when Gnus is shutting down." ;; 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))) @@ -1056,7 +1149,7 @@ function is generally only called when Gnus is shutting down." (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 @@ -1066,13 +1159,13 @@ function is generally only called when Gnus is shutting down." 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) @@ -1088,10 +1181,12 @@ function is generally only called when Gnus is shutting down." (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))) @@ -1103,14 +1198,17 @@ function is generally only called when Gnus is shutting down." (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) @@ -1133,7 +1231,7 @@ function is generally only called when Gnus is shutting down." (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 @@ -1166,15 +1264,17 @@ function is generally only called when Gnus is shutting down." (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 @@ -1183,16 +1283,16 @@ function is generally only called when Gnus is shutting down." 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)) @@ -1213,7 +1313,7 @@ function is generally only called when Gnus is shutting down." (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) @@ -1261,12 +1361,13 @@ function is generally only called when Gnus is shutting down." (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) @@ -1279,12 +1380,13 @@ to be used within a IMAP SEARCH query." (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) @@ -1314,86 +1416,67 @@ be used in a STORE FLAGS command." "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) diff --git a/lisp/nnkiboze.el b/lisp/nnkiboze.el index 1ad6f8c..0da7857 100644 --- a/lisp/nnkiboze.el +++ b/lisp/nnkiboze.el @@ -149,7 +149,7 @@ 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)) @@ -227,11 +227,11 @@ Finds out what articles are to be part of the nnkiboze groups." (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. @@ -242,7 +242,7 @@ Finds out what articles are to be part of the nnkiboze groups." (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 @@ -255,31 +255,31 @@ Finds out what articles are to be part of the nnkiboze groups." (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)) @@ -293,13 +293,13 @@ Finds out what articles are to be part of the nnkiboze groups." 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)))) @@ -319,7 +319,7 @@ Finds out what articles are to be part of the nnkiboze groups." ;; 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 diff --git a/lisp/nnlistserv.el b/lisp/nnlistserv.el index 666cd70..3098bf0 100644 --- a/lisp/nnlistserv.el +++ b/lisp/nnlistserv.el @@ -24,18 +24,13 @@ ;;; 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) @@ -98,7 +93,7 @@ (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 "^

  • *\\([^\\>]+\\) *<[^>]+>\\([^>]+\\)<" nil t) (setq url (match-string 1) @@ -124,7 +119,7 @@ (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 "" 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")) @@ -645,8 +617,8 @@ (search-forward "" 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 @@ -667,7 +639,7 @@ (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)) @@ -679,22 +651,22 @@ (if (> (skip-chars-forward "\040\n\r\t") 0) (delete-region (point-min) (point))) (while (not (eobp)) - (cond - ((looking-at "
    \r?\n?") 
    +	    (cond
    +	     ((looking-at "
    \r?\n?")
     	      (delete-region (match-beginning 0) (match-end 0))
     	      (setq p (point))
     	      (when (search-forward "
    " 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 "

    \n" "<#/external>") @@ -712,8 +684,8 @@ (setq p (point)) (insert "<#part type=\"text/html\" disposition=inline>") (goto-char - (if (re-search-forward - "[\040\n\r\t]*

    \\|[\040\n\r\t]*

    \\|[\040\n\r\t]*

    $" 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)))))) @@ -303,10 +307,11 @@ and `altavista'.") (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) @@ -320,55 +325,55 @@ and `altavista'.") 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. @@ -432,17 +437,17 @@ and `altavista'.") ;; 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) @@ -458,19 +463,19 @@ and `altavista'.") ("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." @@ -510,7 +515,7 @@ and `altavista'.") (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 " ")) @@ -545,7 +550,7 @@ and `altavista'.") (let ((body (point-marker))) (search-forward "

    " nil t) (delete-region (point) (point-max)) - (nnweb-remove-markup) + (mm-url-remove-markup) (goto-char (point-min)) (while (looking-at " *$") (gnus-delete-line)) @@ -572,14 +577,15 @@ and `altavista'.") (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" . "") @@ -631,7 +637,7 @@ and `altavista'.") (goto-char (point-min)) (while (search-forward "
    " nil t) (replace-match "\n")) - (nnweb-decode-entities) + (mm-url-decode-entities) (goto-char (point-min)) (while (re-search-forward ".*href=\"\\([^\"]+\\)\">\\([^>]*\\)
    \\([^-]+\\)- \\([^<]+\\)<.*href=\"news:\\([^\"]+\\)\">.*\">\\(.+\\)

    " nil t) @@ -676,14 +682,15 @@ and `altavista'.") (while (re-search-forward "[0-9]+" 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))))) @@ -704,14 +711,16 @@ and `altavista'.") (goto-char (point-min)) (re-search-forward "^

    " nil t)
         (narrow-to-region (point-min) (point))
    -    (search-backward "" nil t 2)
    +    (search-backward "" 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 ""))
    @@ -721,7 +730,7 @@ and `altavista'.")
         (narrow-to-region (point) (point-max))
         (search-forward "" nil t)
         (delete-region (point) (point-max))
    -    (nnweb-remove-markup)
    +    (mm-url-remove-markup)
         (widen)))
     
     (defun nnweb-google-parse-1 (&optional Message-ID)
    @@ -729,40 +738,40 @@ and `altavista'.")
     	(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 "" 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 "
    ]+>") (goto-char (match-end 0))) (if (not (looking-at "]+>")) (skip-chars-forward " \t") (narrow-to-region (point) (search-forward "" 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]*\\([^<]*\\) - ]+\\)" url) (match-string 1 url) url)) @@ -849,75 +858,6 @@ and `altavista'.") (mapcar 'nnweb-insert-html (nth 2 parse)) (insert "\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) - (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 - "]*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 @@ -967,11 +907,6 @@ If FOLLOW-REFRESH is non-nil, redirect refresh url in META." (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 diff --git a/lisp/nnwfm.el b/lisp/nnwfm.el index 130c689..ccabdfa 100644 --- a/lisp/nnwfm.el +++ b/lisp/nnwfm.el @@ -36,11 +36,9 @@ (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) @@ -56,7 +54,7 @@ (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 @@ -116,7 +114,7 @@ (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))) @@ -216,7 +214,7 @@ (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)) @@ -233,7 +231,7 @@ (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)) @@ -279,12 +277,12 @@ (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 @@ -293,18 +291,19 @@ "\\\\[\"\\\\]" ""))) (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 @@ -377,7 +376,7 @@ 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) diff --git a/lisp/pop3.el b/lisp/pop3.el index d12f861..ce619c1 100644 --- a/lisp/pop3.el +++ b/lisp/pop3.el @@ -123,7 +123,7 @@ Used for APOP authentication.") ((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)) @@ -244,11 +244,14 @@ If NOW, use that time instead." (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 @@ -293,7 +296,7 @@ If NOW, use that time instead." (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." diff --git a/lisp/qp.el b/lisp/qp.el index 9875a0b..8c3b828 100644 --- a/lisp/qp.el +++ b/lisp/qp.el @@ -36,7 +36,9 @@ "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 @@ -63,7 +65,7 @@ coding-system." 16))) (insert byte) (delete-char 3) - ;; Why backward-char??? + ;; Why backward-char??? ;;(unless (eq byte 61) ;; 61 is not ?= in XEmacs ;; (backward-char)) )) diff --git a/lisp/rfc1843.el b/lisp/rfc1843.el index c3bb790..87164ba 100644 --- a/lisp/rfc1843.el +++ b/lisp/rfc1843.el @@ -88,7 +88,7 @@ ftp://ftp.math.psu.edu/pub/simpson/chinese/hzp/hzp.doc" 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)) @@ -145,7 +145,7 @@ ftp://ftp.math.psu.edu/pub/simpson/chinese/hzp/hzp.doc" (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) diff --git a/lisp/rfc2045.el b/lisp/rfc2045.el index 70c8c39..ba3116b 100644 --- a/lisp/rfc2045.el +++ b/lisp/rfc2045.el @@ -19,7 +19,7 @@ ;; 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". diff --git a/lisp/rfc2047.el b/lisp/rfc2047.el index 7d04a83..10eff84 100644 --- a/lisp/rfc2047.el +++ b/lisp/rfc2047.el @@ -116,6 +116,14 @@ Valid encodings are nil, `Q' and `B'.") (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." @@ -127,15 +135,26 @@ 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) @@ -157,18 +176,29 @@ Should be called narrowed to the head of the message." 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 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) @@ -316,6 +346,13 @@ The buffer may be narrowed." (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 @@ -323,21 +360,24 @@ The buffer may be narrowed." (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) @@ -351,7 +391,10 @@ The buffer may be narrowed." (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) ?=) @@ -361,17 +404,26 @@ The buffer may be narrowed." (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." @@ -419,7 +471,7 @@ The buffer may be narrowed." (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)) diff --git a/lisp/rfc2104.el b/lisp/rfc2104.el index 3d45982..5496a4f 100644 --- a/lisp/rfc2104.el +++ b/lisp/rfc2104.el @@ -51,7 +51,9 @@ ;;; 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' @@ -64,7 +66,7 @@ (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) @@ -93,7 +95,7 @@ (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))) diff --git a/lisp/score-mode.el b/lisp/score-mode.el index cfc5cc3..9e976e5 100644 --- a/lisp/score-mode.el +++ b/lisp/score-mode.el @@ -1,5 +1,6 @@ ;;; 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 ;; Keywords: news, mail @@ -26,7 +27,7 @@ ;;; 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.") @@ -52,7 +53,7 @@ "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 () diff --git a/lisp/sha1-el.el b/lisp/sha1-el.el new file mode 100644 index 0000000..0c94c2d --- /dev/null +++ b/lisp/sha1-el.el @@ -0,0 +1,432 @@ +;;; sha1-el.el --- SHA1 Secure Hash Algorithm in Emacs-Lisp. + +;; Copyright (C) 1999, 2001 Free Software Foundation, Inc. + +;; Author: Shuhei KOBAYASHI +;; 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". +;; +;; (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 diff --git a/lisp/sieve-manage.el b/lisp/sieve-manage.el new file mode 100644 index 0000000..f99aa39 --- /dev/null +++ b/lisp/sieve-manage.el @@ -0,0 +1,619 @@ +;;; sieve-manage.el --- Implementation of the managesive protocol in elisp +;; Copyright (C) 2001 Free Software Foundation, Inc. + +;; Author: Simon Josefsson + +;; 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 diff --git a/lisp/sieve-mode.el b/lisp/sieve-mode.el new file mode 100644 index 0000000..7c17146 --- /dev/null +++ b/lisp/sieve-mode.el @@ -0,0 +1,204 @@ +;;; sieve-mode.el --- Sieve code editing commands for Emacs +;; Copyright (C) 2001 Free Software Foundation, Inc. + +;; Author: Simon Josefsson + +;; 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 diff --git a/lisp/sieve.el b/lisp/sieve.el new file mode 100644 index 0000000..857804d --- /dev/null +++ b/lisp/sieve.el @@ -0,0 +1,348 @@ +;;; sieve.el --- Utilities to manage sieve scripts +;; Copyright (C) 2001 Free Software Foundation, Inc. + +;; Author: Simon Josefsson + +;; 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 "" + "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 diff --git a/lisp/smiley-ems.el b/lisp/smiley-ems.el index 8e0cae3..f8a91d9 100644 --- a/lisp/smiley-ems.el +++ b/lisp/smiley-ems.el @@ -1,6 +1,6 @@ ;;; smiley-ems.el --- displaying smiley faces -;; Copyright (C) 2000 Free Software Foundation, Inc. +;; Copyright (C) 2000, 2001 Free Software Foundation, Inc. ;; Author: Dave Love ;; Keywords: news mail multimedia @@ -50,13 +50,17 @@ ;; 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") @@ -67,17 +71,36 @@ rgexp to replace with IMAGE. IMAGE is the name of a PBM file in :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.") @@ -92,7 +115,8 @@ rgexp to replace with IMAGE. IMAGE is the name of a PBM file in ;;;###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)) @@ -102,25 +126,25 @@ rgexp to replace with IMAGE. IMAGE is the name of a PBM file in (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. @@ -145,11 +169,18 @@ With arg, turn displaying on if and only if arg is positive." "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) diff --git a/lisp/smiley.el b/lisp/smiley.el index c74d3ee..d82cbb3 100644 --- a/lisp/smiley.el +++ b/lisp/smiley.el @@ -1,5 +1,6 @@ ;;; 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 @@ -36,6 +37,8 @@ ;; The smilies were drawn by Joe Reiss . +;;; Code: + (require 'cl) (require 'custom) @@ -49,7 +52,7 @@ :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") @@ -227,8 +230,7 @@ above them." "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") @@ -249,8 +251,7 @@ Note -- this function hasn't been implemented yet." ;; 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) @@ -334,7 +335,7 @@ Mouse button3 - menu")) (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))) @@ -399,7 +400,7 @@ With arg, turn displaying on if and only if arg is positive." ;; 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 @@ -408,7 +409,7 @@ With arg, turn displaying on if and only if arg is positive." (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 diff --git a/lisp/smime.el b/lisp/smime.el index 7035ac8..49fabbc 100644 --- a/lisp/smime.el +++ b/lisp/smime.el @@ -41,6 +41,9 @@ ;; 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: @@ -89,9 +92,11 @@ ;; 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. -;; +;; 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 @@ -103,11 +108,13 @@ ;; Also, I'm not going to mention anything about the wonders of ;; cryptopolitics. Oops, I just did. ;; -;; +;; 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: @@ -119,14 +126,17 @@ "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: @@ -139,14 +149,14 @@ certificate." :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 @@ -160,30 +170,39 @@ and the files themself should be in PEM format." (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 () @@ -206,32 +225,49 @@ If nil, use system defaults." (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) @@ -239,18 +275,26 @@ private key and certificate." 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 @@ -262,11 +306,12 @@ KEYFILE should contain a PEM encoded key and certificate." (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. @@ -284,69 +329,98 @@ nil." ;; 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 @@ -360,41 +434,52 @@ Uses current buffer if BUFFER is nil, queries user of KEYFILE is nil." ;; 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." diff --git a/lisp/uudecode.el b/lisp/uudecode.el index b7168c6..8e2fd66 100644 --- a/lisp/uudecode.el +++ b/lisp/uudecode.el @@ -1,6 +1,6 @@ ;;; 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 ;; Keywords: uudecode news @@ -24,35 +24,17 @@ ;;; 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. @@ -66,6 +48,12 @@ input and write the converted data to its standard output." :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]+\\(.*\\)$") @@ -135,86 +123,92 @@ used is specified by `uudecode-decoder-program'." (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) diff --git a/lisp/webmail.el b/lisp/webmail.el index 27fc0eb..b98bb69 100644 --- a/lisp/webmail.el +++ b/lisp/webmail.el @@ -48,21 +48,16 @@ (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))) ;;; @@ -226,31 +221,6 @@ (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) @@ -265,15 +235,15 @@ (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." @@ -315,7 +285,7 @@ (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) @@ -357,7 +327,7 @@ (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)) @@ -459,9 +429,8 @@ (if (not (search-forward "" 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")) @@ -492,9 +461,8 @@ (setq p (match-beginning 0)) (search-forward "" 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)) @@ -514,7 +482,7 @@ (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) @@ -549,9 +517,8 @@ (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) @@ -646,9 +613,8 @@ (setq p (match-beginning 0)) (search-forward "" 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)) @@ -664,9 +630,8 @@ (if (not (search-forward "
    " 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") @@ -679,7 +644,7 @@ (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") @@ -774,9 +739,8 @@ (goto-char (point-min)) (while (re-search-forward "
    " 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>") @@ -804,9 +768,8 @@ (goto-char (point-min)) (while (search-forward "" 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)) @@ -848,7 +811,7 @@ (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) @@ -932,9 +895,8 @@ (goto-char (point-min)) (while (search-forward "" 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)) @@ -976,7 +938,7 @@ (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) @@ -1056,7 +1018,7 @@ (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" @@ -1093,9 +1055,8 @@ (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]* + + * gnus.texi (Choosing Commands): Addition. + +2001-12-31 Rui Zhu + + * emacs-mime.texi (Customization): Typo fix. + +2001-12-31 Lars Magne Ingebrigtsen + + * gnus.texi (Article Display): Addition. + + * emacs-mime.texi (Interface Functions): Addition. + + * gnus.texi (Using MIME): Addition. + +2001-12-30 Lars Magne Ingebrigtsen + + * 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 + + * emacs-mime.texi (Customization): Added example. + + * gnus.texi (Selecting a Group): Addition. + (Tree Display): Addition. + +2001-12-26 Florian Weimer + + * gnus.texi (Using GPG): Remove obsolete reference to gpg-2comp. + +2001-12-26 Simon Josefsson + + * gnus.texi (Summary Buffer Lines): Add xrefs. Suggested by + Arcady Genkin . + +2001-12-26 Katsumi Yamaoka + + * gnus.texi (NNTP): Add a note for `nntp-prepare-post-hook'. + +2001-12-18 Josh Huber + + * ChangeLog, gnus.texi, emacs-mime.texi: (oops) removed + buffer-file-coding-system + +2001-12-18 00:00:00 ShengHuo ZHU + + * ChangeLog, gnus.texi, emacs-mime.texi: Local Variables `coding' + MUST be added! + +2001-12-17 Josh Huber + + * 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 + + * gnus.texi (Saving Articles): Add muttprint. + (Article Commands): Mention muttprint. + +2001-12-15 Simon Josefsson + + * gnus.texi (Virtual Groups): Fix. From Raymond Scholz + . + +2001-12-15 08:00:00 ShengHuo ZHU + + * gnus.texi, emacs-mime.texi: Fix the header. + +2001-12-12 Didier Verna + + * 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,A_(Bjohann + + * gnus.texi (Advanced Scoring Examples): Clarify that the + examples are rules, not complete score files. + +2001-12-09 Nevin Kapur + + * gnus.texi (Expiring Mail): Add. + +2001-12-05 Kai Gro,A_(Bjohann + + * gnus.texi (Splitting in IMAP): Typo. From Colin Marquardt + . + +2001-12-03 10:00:00 ShengHuo ZHU + + * infohack.el (infohack): To process write-protected files safely, + make this buffer be writable after `find-file'. + From TSUCHIYA Masatoshi + +2001-12-03 08:00:00 ShengHuo ZHU + + * Makefile.in: Dependence. + + * emacs-mime.texi: Add coding header. + +2001-12-01 Simon Josefsson + + * gnus.texi (Group Line Specification, Summary Buffer Lines): + Cross reference Positioning Point. + +2001-11-25 09:00:00 ShengHuo ZHU + + * gnus.texi (Limiting): Addition. + +2001-11-19 Simon Josefsson + + * 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 . + +2001-11-17 Simon Josefsson + + * message.texi (Insertion): Use C-c C-u for Importance: instead of + C-c C-p (used by SC). + +2001-11-15 Simon Josefsson + + * 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 + + * gnus.texi (Various Summary Stuff): Add gnus-newsgroup-variables. + +2001-11-15 11:00:00 ShengHuo ZHU + + * message.texi (Security): @uref not @url. + +2001-11-15 Per Abrahamsen + + * 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 + + * gnus.texi (Article Washing): Add `W s'. + +2001-11-12 Simon Josefsson + + * gnus.texi (Security, Using GPG): + * message.texi (Security): + * emacs-mime.texi (MML Definition): Add PGP. + +2001-11-09 Kai Gro,A_(Bjohann + + * message.texi (Movement): message-beginning-of-line. + +2001-11-07 Simon Josefsson + + * sieve.texi (Examples): Add. + (Top): Add. + + * gnus.texi (Saving Articles): Add gnus-summary-write-to-file. + +2001-11-07 Simon Josefsson + + * gnus.texi (Misc Group Stuff): Add cross reference to Composing + Messages. Suggested by "Golubev I. N." . + +2001-11-04 09:00:00 ShengHuo ZHU + + * gnus.texi: Use C-M- instead of M-C-. + * message.texi (Insertion): Ditto. + * sieve.texi (Managing Sieve): Ditto. + Suggested by Eli Zaretskii . + +2001-11-02 Simon Josefsson + + * dir (File): Add Sieve. + + * gnus.texi (Sieve Commands): Add crossposting. + +2001-11-01 23:00:00 ShengHuo ZHU + + * texi2latex.el (latexi-translate): Typo. + (latexi-translate-file): Nine in a herd is enough. + +2001-11-01 Simon Josefsson + + * 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 + + * gnus.texi (Article Washing): Add a note. + +2001-11-01 Simon Josefsson + + * 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 + + * gnus.texi (Group Parameters): Add integer `display'. + (IMAP): Fix. + +2001-10-31 Katsumi Yamaoka + + * gnus.texi (NNTP): Added documentation for + `nntp-prepare-post-hook'. + +2001-10-29 Simon Josefsson + + * gnus.texi (Customizing Articles): Sort list. Remove + duplicate. Suggested by Henrik Holm . + +2001-10-27 Simon Josefsson + + * message.texi (Insertion): Fix message-yank*-prefix. + +2001-10-25 Simon Josefsson + + * gnus.texi (Mail Source Specifiers): More info on SSL, kerberos etc. + (IMAP): Ditto. Suggested by Martin Blais . + +2001-10-23 Per Abrahamsen + + * gnus.texi (Posting Server): Use `native' instead of `nil' for + posting to native server. + +2001-10-22 Kai Gro,A_(Bjohann + + * dir (File): Add standard explanation header. + +2001-10-21 Kai Gro,A_(Bjohann + + * 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 + + * 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,A_(Bjohann + + * gnus.texi (Finding the News): Disrecommend nnspool for Leafnode + users. + +2001-10-17 21:00:00 ShengHuo ZHU + + * gnus.texi (Archived Messages): Add new line after @item. + From: Jesper Harder + +2001-10-17 21:00:00 ShengHuo ZHU + + * gnus.texi (Formatting Basics): Extended format specs. + +2001-10-17 Per Abrahamsen + + * gnus.texi (Summary Buffer Lines): Documment %( and %). + +2001-09-04 21:43:05 Lars Magne Ingebrigtsen + + * gnus.texi (Topic Sorting): Addition. + +2001-10-13 19:00:00 ShengHuo ZHU + + * refcard.tex, gnusref.tex: Merge with the version + from Felix Natter + +2001-10-13 12:00:00 ShengHuo ZHU + + * refcard.tex: Set version to Oort. + + * gnusref.tex: New key bindings in Oort Gnus. + +2001-10-12 18:00:00 ShengHuo ZHU + + * Makefile.in (.dvi.ps): Use TEXPICTS. + (.latexi.dvi-x): Remove gnus.toc as well. + + * gnuslogo-refcard.eps: Remove BeginProcSet. + +2001-10-12 Simon Josefsson + + * 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 + + * 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 + + * gnus.texi: Add href and bookmarks for pdf version. + +2001-10-06 08:00:00 ShengHuo ZHU + + * Makefile.in (uninstall): Add uninstall. + +2001-10-05 Simon Josefsson + + * Makefile.in (clean): Add gnusconfig.tex. Suggested by Henrik + Enberg . + +2001-10-04 Simon Josefsson + + * gnus.texi (Mail Source Customization): Add. + +2001-10-04 10:00:00 ShengHuo ZHU + + * Makefile.in (dvi): Don't depend on tmps. + +2001-10-03 08:00:00 ShengHuo ZHU + + * emacs-mime.texi (mailcap): rvplayer -> wavplayer. Thanks to + Martin Kretzschmar . + +2001-09-29 Simon Josefsson + + * gnus.texi (Foreign Groups): Fix. Add "mailman". + (Document Groups): Ditto. + +2001-09-28 07:00:00 ShengHuo ZHU + + * 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 + +2001-09-28 00:00:00 ShengHuo ZHU + + * gnusconfig.tex.in: Use cmss if pfu is not found. + +2001-09-27 18:00:00 ShengHuo ZHU + + * 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 + + * gnus.texi: Remove the extra white-space. + +2001-09-27 10:00:00 ShengHuo ZHU + + * 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 + + * gnus.texi (Limiting): Addition. + +2001-09-25 23:00:00 ShengHuo ZHU + + * gnus.texi (Pterodactyl Gnus): Put @item in one line. + +2001-09-24 19:00:00 ShengHuo ZHU + + * gnus.texi: eps path fix. + * postamble.tex: Ditto. + * texi2latex.el: Ditto. + + * Makefile.in: Move some to ps/Makefile.in. + +2001-09-24 Simon Josefsson + + * 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 + + * gnus.texi: Use "back end". + +2001-09-23 Simon Josefsson + + * 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 + + * gnus.texi (Other Marks): Add Recent. + +2001-09-14 Simon Josefsson + + * gnus.texi (Mail Folders): Add. + +2001-09-11 Simon Josefsson + + * gnus.texi (Delayed Articles): Fix. Suggested by Paul Jarc + . + +2001-09-08 Simon Josefsson + + * gnus.texi (MIME Commands): Add gnus-buttonized-mime-types. + +2001-09-08 Kai Gro,A_(Bjohann + + * 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,A_(Bjohann + + * gnus.texi (Fancy Mail Splitting): Mention `delete' near the + explanation of `junk'. + +2001-09-04 Katsumi Yamaoka + + * 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,A_(Bjohann + + * gnus.texi (Optional Backend Functions): More detail about the + DATE arg for nnchoke-request-newgroups. Reported by Paul Jarc. + +2001-09-01 Kai Gro,A_(Bjohann + + * 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 + From Anders Jackson + + * gnus.texi (Group Parameters): Fix. + +2001-08-27 Simon Josefsson + + * gnus.texi (Archiving Mail): Add. + +2001-08-25 Simon Josefsson + + * gnus.texi (Mail Spool): Add marks. + (MH Spool): Doesn't use marks file. + (Mail Folders): Add marks. + +2001-08-25 Simon Josefsson + From Henrik Enberg + + * gnus.texi (Group Parameters): Fix. + +2001-08-24 16:03:31 Lars Magne Ingebrigtsen + + * gnus.texi (Group Parameters): Fix. + +2001-08-24 Simon Josefsson + + * Makefile.in (latexps): Make tmps. + +2001-08-24 Simon Josefsson + From Jesper Harder + + * Makefile.in (latexps): Escape {. + + * splitindex: Ditto. + +2001-08-23 19:22:59 Lars Magne Ingebrigtsen + + * gnus.texi (Group Parameters): Fix. + (Group Parameters): Addition. + (Limiting): Addition. + +2001-08-21 23:55:48 Lars Magne Ingebrigtsen + + * gnus.texi (Score Variables): Fix. + +2001-08-20 Kai Gro,A_(Bjohann + + * 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 + + * gnus.texi (Other Marks): Addition. + (Positioning Point): New. + (Tabulation): New. + +2001-08-19 Kai Gro,A_(Bjohann + + * 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 + + * gnus.texi (Optional Backend Functions): Remove `set' + request-set-mark action. + +2001-08-18 00:40:10 Lars Magne Ingebrigtsen + + * gnus.texi (Wide Characters): New section. + +2001-08-17 Simon Josefsson + + * gnus.texi: Replace 20,20 with 23,23 for + gnus-summary-line-format. + +2001-08-17 14:24:14 Lars Magne Ingebrigtsen + + * gnus.texi (Group Parameters): Document regexp substitution. + (Group Parameters): Addition. + +2001-08-11 23:00:00 ShengHuo ZHU + From Nevin Kapur + + * gnus.texi (September Gnus): Typo. + +2001-08-12 Simon Josefsson + 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 + + * 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,A_(Bjohann + + * gnus.texi (Summary Mail Commands): Remove duplicate explanation + of `S W'. Reported by Norbert Koch. + +2001-08-09 15:00:00 ShengHuo ZHU + From Benjamin Rutt + + * gnus.texi (Troubleshooting): Addition. + +2001-08-09 Simon Josefsson + From Benjamin Rutt + + * gnus.texi (Mail Backend Variables): Fix. + +2001-08-04 Kai Gro,A_(Bjohann + + * gnus.texi (Summary Buffer Lines): Mention `gnus-goto-colon'. + +2001-08-03 Kai Gro,A_(Bjohann + + * gnus.texi (Backend Interface): Explain about article numbers. + Suggested by Paul Jarc. + +2001-08-02 22:00:00 ShengHuo ZHU + + * emacs-mime.texi (Non-MIME): Addition. + + * gnus.texi (Group Parameters): Addition. + (Mailing List): Addition. + +2001-08-01 Simon Josefsson + + * 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 . + +2001-07-31 Simon Josefsson + + * 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 + From Janne Rinta-Manty + + * gnus.texi (Read Articles): Typo. + +2001-07-25 22:22:22 Raymond Scholz + + * gnus.texi (Fancy Mail Splitting): New variable + nnmail-split-fancy-with-parent-ignore-groups + +2001-07-24 Kai Gro,A_(Bjohann + + * 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 + From Karl Kleinpaste + + * gnus.texi (Summary Buffer Lines): Add %B. + +2001-07-20 11:00:00 ShengHuo ZHU + From Jesper Harder + + * message.texi (Insertion): Addition. + +2001-07-19 22:00:00 ShengHuo ZHU + + * gnus.texi (Charsets): Addition. + +2001-07-17 22:00:00 ShengHuo ZHU + + * gnus.texi (Searching for Articles): Raw articles. + +2001-07-16 Kai Gro,A_(Bjohann + + * message.texi (Insertion): Refer to gnus-cite-attribution-suffix. + +2001-07-13 12:00:00 ShengHuo ZHU + + * gnus.texi (RSS): Add. + From Christoph Conrad . + +2001-07-13 08:00:00 ShengHuo ZHU + + * gnus.texi (Incorporating Old Mail): Add index. + +2001-07-13 00:00:00 ShengHuo ZHU + + * gnus.texi (Group Parameters): Add. + +2001-07-04 Simon Josefsson + + * gnus.texi (IMAP): Add. + +2001-07-04 Didier Verna + + * 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 + From Ralph Schleicher + + * gnus.texi (MIME Commands): Add. + +2001-06-24 Kai Gro,A_(Bjohann + + * gnus.texi (Summary Score Commands): Say that some commands + create ADAPT files. + +2001-06-23 Kai Gro,A_(Bjohann + + * gnus.texi (Duplicates): Contents of Gnus-Warning header have + changed. Reported by Peter J Acklam. + +2001-06-19 Simon Josefsson + + * gnus.texi (IMAP): Fix `imtest' discussion. + + * gnus-faq.texi (Frequently Asked Questions): Fix URL. + +2001-06-17 Kai Gro,A_(Bjohann + + * gnus.texi (Group Line Specification): Explain why %t is only an + estimate. + +2001-06-16 Simon Josefsson + + * gnus.texi (IMAP): Add. + +2001-06-13 15:00:00 ShengHuo ZHU + + * gnus.texi (Article Washing): Add. + +2001-06-11 09:00:00 ShengHuo ZHU + + * gnus.texi: behaviour -> behavior. Suggested by Eli Zaretskii + . + +2001-06-09 20:00:00 ShengHuo ZHU + + * gnus.texi: Apply "overfull hbox" patch from Eli Zaretskii + . + +2001-06-07 16:00:00 ShengHuo ZHU + + * gnus.texi (RSS): Add. + +2001-05-31 13:00:00 ShengHuo ZHU + + * gnus.texi (Setting Marks): Add. + +2001-05-27 Simon Josefsson + + * message.texi (Insertion): Add message-yank-cited-prefix. + +2001-05-22 Simon Josefsson + From Jesper Harder + + * gnus.texi (Article Washing): Add. + +2001-05-16 Simon Josefsson + From Jesper Harder + + * texi2latex.el (latexi-translate-file): Also exchange ref. + + * gnus.texi: Add \gnusref and \gnusuref. + +2001-05-16 Simon Josefsson + From Raymond Scholz + + * gnus.texi (Using MIME): Add and fix. + +2001-05-05 Florian Weimer + + * gnus.texi (IMAP): Remove double paragraph (suggest by Norbert + Koch), fix NNTP reference. + +2001-05-04 08:00:00 ShengHuo ZHU + Suggested by Dan Christensen + + * gnus.texi (Mail Group Commands): Add pxref. + (Group Maintenance): Ditto. + (Topic Commands): Ditto. + (Expiring Mail): Typo. + +2001-05-04 08:00:00 ShengHuo ZHU + From Raymond Scholz + + * gnus.texi (Summary Buffer Lines): Mention the meaning of a + colon. + +2001-05-03 07:00:00 ShengHuo ZHU + From Sriram Karra . + + * gnus.texi: Add default value. + +2001-05-03 06:00:00 ShengHuo ZHU + + * gnus.texi (Using GPG): Use example environment. + +2001-05-02 17:00:00 ShengHuo ZHU + + * gnus.texi (Expunging mailboxes): Typo. + 2001-04-15 19:38:54 Lars Magne Ingebrigtsen * gnus.texi (Mail and Post): Fix. @@ -52,7 +850,7 @@ 2001-03-11 Kai Gro,A_(Bjohann * message.texi (Message Headers): Update doc for - `message-generate-headers-first'. + `message-generate-headers-first'. 2001-03-14 15:00:00 ShengHuo ZHU From Nevin Kapur @@ -78,13 +876,13 @@ * 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 * 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 @@ -137,7 +935,7 @@ 2001-02-06 19:00:00 ShengHuo ZHU * gnus.texi (Using GPG): Key binding. - + * message.texi (Security): Ditto. 2001-02-06 18:00:00 ShengHuo ZHU @@ -162,7 +960,7 @@ * message.texi (message-ignored-news-headers): Add "X-Draft-From:". (message-ignored-mail-headers): Ditto. - + 2001-01-21 Raymond Scholz * message.texi: Rename X-Mailer and X-Newsreader to User-Agent. @@ -200,7 +998,7 @@ 2001-01-10 15:00:00 ShengHuo ZHU - * 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 @@ -234,7 +1032,7 @@ 2001-01-03 Kai Gro,A_(Bjohann * 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 @@ -373,7 +1171,7 @@ * 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,A_(Bjohann @@ -523,7 +1321,7 @@ 2000-07-03 00:24:55 Lars Magne Ingebrigtsen - * 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. @@ -578,7 +1376,7 @@ 2000-04-26 02:30:06 Shenghuo ZHU - * gnus.texi (Posting Styles): Addition. + * gnus.texi (Posting Styles): Addition. 2000-04-24 17:09:17 Felix Natter @@ -1198,7 +1996,7 @@ Thu Feb 25 00:28:49 1999 Shenghuo ZHU 1998-08-27 07:29:17 Lars Magne Ingebrigtsen * gnus.texi (Mail Folders): Addition. - + ;; Local Variables: ;; coding: iso-2022-7bit ;; End: diff --git a/texi/Makefile.in b/texi/Makefile.in index d35f8ee..dd4d951 100644 --- a/texi/Makefile.in +++ b/texi/Makefile.in @@ -12,49 +12,52 @@ EMACS=@EMACS@ 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: @@ -62,7 +65,8 @@ 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 @@ -71,45 +75,77 @@ makeinfo: 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 \ @@ -119,15 +155,15 @@ out: 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) @@ -148,66 +184,48 @@ install: $(INFO_DEPS) 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: diff --git a/texi/dir b/texi/dir index 08eb94d..3877572 100644 --- a/texi/dir +++ b/texi/dir @@ -1,10 +1,22 @@ -*- 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.  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" 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. diff --git a/texi/emacs-mime.texi b/texi/emacs-mime.texi index a41377b..16ed3f8 100644 --- a/texi/emacs-mime.texi +++ b/texi/emacs-mime.texi @@ -1,4 +1,4 @@ -\input texinfo @c -*-texinfo-*- +\input texinfo @setfilename emacs-mime @settitle Emacs MIME Manual @@ -18,7 +18,7 @@ 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 @@ -240,7 +240,20 @@ at the beginning of the narrowed buffer. @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 @@ -785,7 +798,7 @@ audio/wav; wavplayer %s @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. @@ -824,6 +837,7 @@ returned as a result of this analysis. @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. @@ -839,6 +853,62 @@ a @sc{mime} article. If given a multipart message, it will recursively 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 @@ -964,10 +1034,13 @@ last possible part of a message, as that is supposed to be the richest. 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 @@ -980,7 +1053,7 @@ library will display it externally (e.g. with @samp{ImageMagick} or 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 @@ -1146,12 +1219,12 @@ RFC822 date when the part was read (@code{Content-Disposition}). 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 @@ -1361,7 +1434,7 @@ if not identical. 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 @@ -1419,4 +1492,8 @@ Content-Disposition Header Field @contents @bye + +@c Local Variables: +@c mode: texinfo +@c coding: iso-8859-1 @c End: diff --git a/texi/etc/bar.xpm b/texi/etc/bar.xpm new file mode 100644 index 0000000..2985065 --- /dev/null +++ b/texi/etc/bar.xpm @@ -0,0 +1,54 @@ +/* XPM */ +static char * picon-bar_xpm[] = { +"6 48 2 1", +" c white s background", +". c black", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. ", +" .. "}; diff --git a/texi/etc/gnus-group-catchup-current-up.xpm b/texi/etc/gnus-group-catchup-current-up.xpm new file mode 100644 index 0000000..0504f9d --- /dev/null +++ b/texi/etc/gnus-group-catchup-current-up.xpm @@ -0,0 +1,39 @@ +/* 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"}; diff --git a/texi/etc/gnus-group-catchup-current.xpm b/texi/etc/gnus-group-catchup-current.xpm new file mode 100644 index 0000000..bea4643 --- /dev/null +++ b/texi/etc/gnus-group-catchup-current.xpm @@ -0,0 +1,39 @@ +/* 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"}; diff --git a/texi/etc/gnus-group-describe-group-up.xpm b/texi/etc/gnus-group-describe-group-up.xpm new file mode 100644 index 0000000..e0ffde7 --- /dev/null +++ b/texi/etc/gnus-group-describe-group-up.xpm @@ -0,0 +1,39 @@ +/* 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......................", +" ..........................."}; diff --git a/texi/etc/gnus-group-exit-up.xpm b/texi/etc/gnus-group-exit-up.xpm new file mode 100644 index 0000000..1b8982f --- /dev/null +++ b/texi/etc/gnus-group-exit-up.xpm @@ -0,0 +1,39 @@ +/* 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"}; diff --git a/texi/etc/gnus-group-get-new-news-this-group-up.xpm b/texi/etc/gnus-group-get-new-news-this-group-up.xpm new file mode 100644 index 0000000..918fd2e --- /dev/null +++ b/texi/etc/gnus-group-get-new-news-this-group-up.xpm @@ -0,0 +1,39 @@ +/* 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. "}; diff --git a/texi/etc/gnus-group-get-new-news-up.xpm b/texi/etc/gnus-group-get-new-news-up.xpm new file mode 100644 index 0000000..d324784 --- /dev/null +++ b/texi/etc/gnus-group-get-new-news-up.xpm @@ -0,0 +1,39 @@ +/* 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. "}; diff --git a/texi/etc/gnus-group-kill-group-up.xpm b/texi/etc/gnus-group-kill-group-up.xpm new file mode 100644 index 0000000..e728bf5 --- /dev/null +++ b/texi/etc/gnus-group-kill-group-up.xpm @@ -0,0 +1,38 @@ +/* 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. ", +" .................... ", +" ", +" ", +" "}; diff --git a/texi/etc/gnus-group-subscribe-up.xpm b/texi/etc/gnus-group-subscribe-up.xpm new file mode 100644 index 0000000..15f7d43 --- /dev/null +++ b/texi/etc/gnus-group-subscribe-up.xpm @@ -0,0 +1,38 @@ +/* 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. ", +" .................... ", +" ", +" ", +" "}; diff --git a/texi/etc/gnus-group-unsubscribe-up.xpm b/texi/etc/gnus-group-unsubscribe-up.xpm new file mode 100644 index 0000000..7c7ce5b --- /dev/null +++ b/texi/etc/gnus-group-unsubscribe-up.xpm @@ -0,0 +1,38 @@ +/* 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. ", +" .................... ", +" ", +" ", +" "}; diff --git a/texi/etc/gnus-summary-caesar-message-up.xpm b/texi/etc/gnus-summary-caesar-message-up.xpm new file mode 100644 index 0000000..6f56aa9 --- /dev/null +++ b/texi/etc/gnus-summary-caesar-message-up.xpm @@ -0,0 +1,38 @@ +/* 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. ", +" .................... ", +" ", +" ", +" "}; diff --git a/texi/etc/gnus-summary-cancel-article-up.xpm b/texi/etc/gnus-summary-cancel-article-up.xpm new file mode 100644 index 0000000..fa7c639 --- /dev/null +++ b/texi/etc/gnus-summary-cancel-article-up.xpm @@ -0,0 +1,39 @@ +/* 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. ... ... ... ...", +"................................", +"................................", +"................................", +" ... ... ... ... ... ... ... ...", +"................................", +"................................", +"................................", +" ... ... ... ... ... ... ... ...", +"................................", +"................................", +"................................", +" ... ... ... ... ... ... ... ...", +"................................", +"................................", +"................................"}; diff --git a/texi/etc/gnus-summary-catchup-and-exit-up.xpm b/texi/etc/gnus-summary-catchup-and-exit-up.xpm new file mode 100644 index 0000000..a5d8ba6 --- /dev/null +++ b/texi/etc/gnus-summary-catchup-and-exit-up.xpm @@ -0,0 +1,39 @@ +/* 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"}; diff --git a/texi/etc/gnus-summary-catchup-up.xpm b/texi/etc/gnus-summary-catchup-up.xpm new file mode 100644 index 0000000..9de9baf --- /dev/null +++ b/texi/etc/gnus-summary-catchup-up.xpm @@ -0,0 +1,37 @@ +/* XPM */ +static char * icon-catchup2_xpm[] = { +"32 32 2 1", +" c #000000000000", +". c #BFBFBFBFBFBF s backgroundToolBarColor", +" ... ... ... ... ... ... ... ...", +"................................", +"................................", +"................................", +" ... ... ... ... ... ... ... ...", +"................................", +"................................", +"................. .............", +" ... ... ... ... . ... ... ...", +"................ ..............", +"............... ................", +"................................", +" ... ... ... ... ... ... ... ...", +"................................", +"................................", +"............. .......... .....", +" ... ... ... . ... ... . ...", +"............ .......... ......", +"........... ........... ........", +"............ .......... .......", +" ... ... ... . . ... ... ... ...", +"............... ..... ", +"................ ... ......", +"........ ..... ... ...... .....", +" ... .. .. . . . . .. . .", +"....... .... .... ... .. . ... ", +"...... ...... ... ..... ... ...", +"...... .. .... ...... .. ..", +" ... ... . ... .. .. ..", +"........... .... . .... .", +".......... ..... ..... .. .", +".......... ..... ....... ... "}; diff --git a/texi/etc/gnus-summary-exit-up.xpm b/texi/etc/gnus-summary-exit-up.xpm new file mode 100644 index 0000000..d1ab26a --- /dev/null +++ b/texi/etc/gnus-summary-exit-up.xpm @@ -0,0 +1,37 @@ +/* XPM */ +static char * icon-exit-summary_xpm[] = { +"32 32 2 1", +" c #000000000000", +". c #BFBFBFBFBFBF s backgroundToolBarColor", +" ... ... ... ... ... ... ... ...", +"................................", +"................................", +"................................", +" ... ...... ... ...", +"........ ....... .......", +"........ ........... .......", +"........ .......... .......", +" ... ... ... ....... ... ...", +"................ ... .......", +".................... .......", +"........ .......... .......", +" ... ... ... ....... ... ...", +"........ ....... . .......", +"........ ....... . .......", +"........ ....... . .......", +" ... ... ... ....... ... ...", +"........ .......... .......", +"........ ........... .......", +"................ ... .......", +" ... ....... ....... ... ...", +"........ .......... .......", +"........ ........ . . .......", +"........ .... . . . . ........", +" ... .. .. . . . . ... ...", +"................................", +"................................", +"................................", +" ... ... ... ... ... ... ... ...", +"................................", +"................................", +"................................"}; diff --git a/texi/etc/gnus-summary-followup-up.xpm b/texi/etc/gnus-summary-followup-up.xpm new file mode 100644 index 0000000..3cee12e --- /dev/null +++ b/texi/etc/gnus-summary-followup-up.xpm @@ -0,0 +1,38 @@ +/* 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. "}; diff --git a/texi/etc/gnus-summary-followup-with-original-up.xpm b/texi/etc/gnus-summary-followup-with-original-up.xpm new file mode 100644 index 0000000..baffb6b --- /dev/null +++ b/texi/etc/gnus-summary-followup-with-original-up.xpm @@ -0,0 +1,38 @@ +/* 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. "}; diff --git a/texi/etc/gnus-summary-mail-copy-up.xpm b/texi/etc/gnus-summary-mail-copy-up.xpm new file mode 100644 index 0000000..e73e6d5 --- /dev/null +++ b/texi/etc/gnus-summary-mail-copy-up.xpm @@ -0,0 +1,38 @@ +/* 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... ", +" .......................... ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/texi/etc/gnus-summary-mail-delete-up.xpm b/texi/etc/gnus-summary-mail-delete-up.xpm new file mode 100644 index 0000000..932d8f2 --- /dev/null +++ b/texi/etc/gnus-summary-mail-delete-up.xpm @@ -0,0 +1,39 @@ +/* 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 ", +" ", +" ", +" ", +" "}; diff --git a/texi/etc/gnus-summary-mail-forward-up.xpm b/texi/etc/gnus-summary-mail-forward-up.xpm new file mode 100644 index 0000000..19db803 --- /dev/null +++ b/texi/etc/gnus-summary-mail-forward-up.xpm @@ -0,0 +1,38 @@ +/* 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. ", +" ... ", +" ", +" "}; diff --git a/texi/etc/gnus-summary-mail-get-up.xpm b/texi/etc/gnus-summary-mail-get-up.xpm new file mode 100644 index 0000000..ffdb84c --- /dev/null +++ b/texi/etc/gnus-summary-mail-get-up.xpm @@ -0,0 +1,38 @@ +/* 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... ", +" .......................... ", +" ", +" ", +" "}; diff --git a/texi/etc/gnus-summary-mail-originate-up.xpm b/texi/etc/gnus-summary-mail-originate-up.xpm new file mode 100644 index 0000000..8ba8bc2 --- /dev/null +++ b/texi/etc/gnus-summary-mail-originate-up.xpm @@ -0,0 +1,38 @@ +/* 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... ", +" .......................... ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/texi/etc/gnus-summary-mail-reply-up.xpm b/texi/etc/gnus-summary-mail-reply-up.xpm new file mode 100644 index 0000000..20fe672 --- /dev/null +++ b/texi/etc/gnus-summary-mail-reply-up.xpm @@ -0,0 +1,38 @@ +/* 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... ", +" .......................... ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/texi/etc/gnus-summary-mail-save-up.xpm b/texi/etc/gnus-summary-mail-save-up.xpm new file mode 100644 index 0000000..fd4824b --- /dev/null +++ b/texi/etc/gnus-summary-mail-save-up.xpm @@ -0,0 +1,41 @@ +/* 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. ", +" ................ ", +" "}; diff --git a/texi/etc/gnus-summary-next-unread-up.xpm b/texi/etc/gnus-summary-next-unread-up.xpm new file mode 100644 index 0000000..e525816 --- /dev/null +++ b/texi/etc/gnus-summary-next-unread-up.xpm @@ -0,0 +1,39 @@ +/* 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. "}; diff --git a/texi/etc/gnus-summary-post-news-up.xpm b/texi/etc/gnus-summary-post-news-up.xpm new file mode 100644 index 0000000..46be7c1 --- /dev/null +++ b/texi/etc/gnus-summary-post-news-up.xpm @@ -0,0 +1,38 @@ +/* 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... ", +" .... ", +" ", +" . . . . . . . . ", +" ", +" "}; diff --git a/texi/etc/gnus-summary-prev-unread-up.xpm b/texi/etc/gnus-summary-prev-unread-up.xpm new file mode 100644 index 0000000..b2088fb --- /dev/null +++ b/texi/etc/gnus-summary-prev-unread-up.xpm @@ -0,0 +1,39 @@ +/* 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. "}; diff --git a/texi/etc/gnus-summary-reply-up.xpm b/texi/etc/gnus-summary-reply-up.xpm new file mode 100644 index 0000000..255f7a1 --- /dev/null +++ b/texi/etc/gnus-summary-reply-up.xpm @@ -0,0 +1,39 @@ +/* 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"}; diff --git a/texi/etc/gnus-summary-reply-with-original-up.xpm b/texi/etc/gnus-summary-reply-with-original-up.xpm new file mode 100644 index 0000000..1135bfa --- /dev/null +++ b/texi/etc/gnus-summary-reply-with-original-up.xpm @@ -0,0 +1,39 @@ +/* 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"}; diff --git a/texi/etc/gnus-summary-save-article-file-up.xpm b/texi/etc/gnus-summary-save-article-file-up.xpm new file mode 100644 index 0000000..ea30122 --- /dev/null +++ b/texi/etc/gnus-summary-save-article-file-up.xpm @@ -0,0 +1,41 @@ +/* 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. ", +" ................ ", +" "}; diff --git a/texi/etc/gnus-summary-save-article-up.xpm b/texi/etc/gnus-summary-save-article-up.xpm new file mode 100644 index 0000000..fd4824b --- /dev/null +++ b/texi/etc/gnus-summary-save-article-up.xpm @@ -0,0 +1,41 @@ +/* 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. ", +" ................ ", +" "}; diff --git a/texi/etc/gnus-uu-decode-uu-up.xpm b/texi/etc/gnus-uu-decode-uu-up.xpm new file mode 100644 index 0000000..568315c --- /dev/null +++ b/texi/etc/gnus-uu-decode-uu-up.xpm @@ -0,0 +1,39 @@ +/* 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. ", +" ................... ", +" ", +" ", +" "}; diff --git a/texi/etc/gnus-uu-post-news-up.xpm b/texi/etc/gnus-uu-post-news-up.xpm new file mode 100644 index 0000000..f4a7e3a --- /dev/null +++ b/texi/etc/gnus-uu-post-news-up.xpm @@ -0,0 +1,39 @@ +/* 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 .. ...", +"....... ......", +"................................", +"................................"}; diff --git a/texi/etc/gnus.xpm b/texi/etc/gnus.xpm new file mode 100644 index 0000000..b51c903 --- /dev/null +++ b/texi/etc/gnus.xpm @@ -0,0 +1,283 @@ +/* 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" +}; diff --git a/texi/gnus-faq.texi b/texi/gnus-faq.texi index abc9054..f3830b7 100644 --- a/texi/gnus-faq.texi +++ b/texi/gnus-faq.texi @@ -1,6 +1,6 @@ @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 @@ -8,7 +8,7 @@ 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 @@ -38,19 +38,19 @@ Any of the following locations: @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 @@ -113,7 +113,7 @@ XEmacs | 19.29 XEmacs 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. @@ -130,40 +130,40 @@ on it (unless you use Gnus as your mailer reader, that is). The mailing 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 @@ -211,7 +211,7 @@ Mailcrypt. 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. @@ -221,7 +221,7 @@ a two-step process unlike most other packages, so you should 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: @@ -306,7 +306,9 @@ The most vital entries in my (still young) all.SCORE: (("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 @@ -334,13 +336,17 @@ I would like to contribute with mine. ;; $$$ 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 @@ -383,12 +389,19 @@ excessively cross posted articles. ("^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 @@ -404,7 +417,7 @@ something like: @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 @@ -486,9 +499,9 @@ in your @file{.gnus} instead. @item Q3.1 How do I convert my kill files to score files? -A kill-to-score translator was written by Ethan Bradford -. 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 @@ -526,8 +539,9 @@ Luis Fernandes writes:@* 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 () @@ -580,7 +594,7 @@ Send mail to @file{majordomo@@edmonds.home.cs.ubc.ca} with the following 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 diff --git a/texi/gnus.texi b/texi/gnus.texi index 90d777e..30b8189 100644 --- a/texi/gnus.texi +++ b/texi/gnus.texi @@ -1,4 +1,4 @@ -\input texinfo @c -*-texinfo-*- -*- coding: iso-latin-1 -*- +\input texinfo @setfilename gnus @settitle Gnus Manual @@ -20,26 +20,39 @@ \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}'} @@ -50,6 +63,7 @@ \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}} @@ -67,7 +81,7 @@ \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} } @@ -106,7 +120,7 @@ } \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]{ @@ -186,9 +200,9 @@ { \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 } @@ -210,9 +224,9 @@ { \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 } @@ -234,9 +248,9 @@ { \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 } @@ -257,10 +271,10 @@ \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} @@ -272,7 +286,7 @@ \thispagestyle{empty} -Copyright \copyright{} 1995, 1996, 1997, 1998, 1999, 2000 +Copyright \copyright{} 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. @@ -301,7 +315,8 @@ license to the document, as described in section 6 of the license. 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 @@ -330,7 +345,8 @@ license to the document, as described in section 6 of the license. @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 @@ -397,82 +413,83 @@ the program. @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 @@ -481,6 +498,7 @@ 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. @@ -501,76 +519,84 @@ Summary Buffer * 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 @@ -579,103 +605,116 @@ 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 @@ -683,39 +722,33 @@ 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 @@ -725,29 +758,30 @@ 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 @@ -757,116 +791,118 @@ 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 @@ -894,17 +930,17 @@ If you puzzle at any terms used in this manual, please refer to the 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 @@ -934,7 +970,8 @@ If you want to read directly from the local spool, say: @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 @@ -980,8 +1017,8 @@ files during startup (if that's required), and new newsgroups that 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 ""))) @@ -1098,13 +1135,13 @@ also save you some time at startup. Even if this variable is @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 @@ -1193,7 +1230,7 @@ Kill all new groups. @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 @@ -1201,7 +1238,7 @@ 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 @@ -1260,7 +1297,7 @@ Yet another variable that meddles here is 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}. @@ -1491,7 +1528,7 @@ performance, but if the server does not support the aforementioned @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. @@ -1565,6 +1602,26 @@ default is @samp{Tuxedomoon.Jingle4.au}. @chapter Group Buffer @cindex group buffer +@c Alex Schroeder suggests to rearrange this as follows: +@c +@c 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 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 First, "Gnus considers groups... (default 9)." +@c New, a table summarizing what levels 1 to 9 mean. +@c Third, "Gnus treats subscribed ... reasons of efficiency" +@c 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. @@ -1572,7 +1629,7 @@ 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}} @@ -1584,23 +1641,23 @@ long as Gnus is active. @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 @@ -1608,9 +1665,9 @@ long as Gnus is active. @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 @@ -1645,10 +1702,10 @@ a @code{printf} specifications, for those of you who use (feh!) C. @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 @@ -1683,6 +1740,15 @@ Number of read articles. 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. @@ -1976,8 +2042,8 @@ This is yet one more command that does the same as the @kbd{RET} 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 @@ -1999,44 +2065,35 @@ be fetched. @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. @@ -2380,7 +2437,7 @@ to subscribe to @sc{nntp} groups, @pxref{Browse Foreign Server}. 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) @@ -2446,7 +2503,7 @@ strings to match on headers (@code{gnus-group-make-kiboze-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 @@ -2457,10 +2514,12 @@ Read an arbitrary directory as if it were a newsgroup with the 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 @@ -2591,6 +2650,11 @@ If you do an @kbd{a} command in a mail group and you don't have a @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 @@ -2669,12 +2733,14 @@ Elements that look like @code{(adapt-file . "file")} will make 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: @@ -2682,18 +2748,52 @@ 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. @@ -2701,13 +2801,15 @@ 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 @@ -2724,13 +2826,40 @@ like this in the group parameters: (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}, @@ -2753,6 +2882,34 @@ presents you with a Customize-like interface. The latter helps avoid 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 @@ -2973,7 +3130,7 @@ Sort the group buffer by group rank @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 @@ -3020,7 +3177,7 @@ Sort the groups by group rank @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 @@ -3053,12 +3210,14 @@ zombies. @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 @@ -3192,7 +3351,7 @@ groups or the sex groups---or both! Go wild! @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 @@ -3219,69 +3378,28 @@ To get this @emph{fab} functionality you simply turn on (ooh!) the 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 @@ -3290,6 +3408,16 @@ When the topic minor mode is turned on, a new @kbd{T} submap will be 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 @@ -3298,6 +3426,77 @@ definitions slightly. 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 @@ -3308,7 +3507,7 @@ convention (@pxref{Process/Prefix}). @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) @@ -3373,50 +3572,12 @@ Mark all groups in the current topic with the process mark 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) @@ -3446,6 +3607,48 @@ Edit the topic parameters (@code{gnus-topic-edit-parameters}). @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 @@ -3488,9 +3691,15 @@ Sort the current topic by group rank @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. @@ -3553,10 +3762,15 @@ parameters: @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 @@ -3607,10 +3821,11 @@ happens. You just have to be careful if you do stuff like that. @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 @@ -3624,13 +3839,33 @@ Enter the server buffer (@code{gnus-group-enter-server-mode}). @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 @@ -3671,9 +3906,11 @@ For example: @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 @@ -3698,7 +3935,7 @@ Check the server(s) for new articles. If the numerical prefix is used, 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) @@ -3868,7 +4105,69 @@ file(s) whether Gnus thinks it is necessary or not. @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 @@ -3886,6 +4185,7 @@ You can have as many summary buffers open as you wish. * 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. @@ -3911,6 +4211,7 @@ You can have as many summary buffers open as you wish. * 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 @@ -3921,17 +4222,17 @@ You can have as many summary buffers open as you wish. @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 @@ -3966,9 +4267,17 @@ the @code{gnus-summary-line-format} variable. It works along the same 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 @@ -3998,10 +4307,13 @@ the @code{a} spec. @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). @@ -4016,12 +4328,12 @@ One space for each thread level. @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}). @@ -4055,6 +4367,9 @@ article has any children. 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 @@ -4064,6 +4379,10 @@ argument. The function should return a string, which will be inserted 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'' @@ -4142,7 +4461,7 @@ In summary, you'd typically put something like the following in '(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 @@ -4341,8 +4660,8 @@ the given number of lines from the top. @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 @@ -4416,8 +4735,9 @@ Go to the first unread article @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 @@ -4531,8 +4851,8 @@ If given a numerical prefix, you can do semi-manual charset stuff. 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 @@ -4576,7 +4896,7 @@ Select the article buffer (@code{gnus-summary-select-article-buffer}). * 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 @@ -4633,13 +4953,6 @@ that goes out to all people listed in the @code{To}, @code{From} (or @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) @@ -4663,8 +4976,24 @@ default, the message is decoded and forwarded as an rfc822 MIME section. @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) @@ -4724,7 +5053,8 @@ command understands the process/prefix convention @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 @@ -4741,8 +5071,9 @@ Commands for posting a news article: @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 @@ -4780,7 +5111,7 @@ the process/prefix convention. @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 @@ -4808,7 +5139,8 @@ Uuencode a file, split it into parts, and post it as a series (@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 @@ -4881,6 +5213,103 @@ canceled/superseded. 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 @@ -4897,9 +5326,9 @@ neologism ohoy!) of the article. Alphabetic marks generally mean 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 @@ -5004,7 +5433,7 @@ Threading}. @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 @@ -5050,9 +5479,14 @@ answered) will be marked with an @samp{A} in the second column (@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 @@ -5065,6 +5499,18 @@ religiously) are marked with an @samp{S} in the second column (@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 @@ -5169,9 +5615,15 @@ articles (@code{gnus-summary-catchup-all}). @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 @@ -5407,20 +5859,23 @@ additional articles. @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 @@ -5465,6 +5920,14 @@ the stack. 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) @@ -5514,6 +5977,18 @@ Mark all excluded unread articles as read (@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 @@ -5564,8 +6039,8 @@ displayed as empty lines in the summary buffer. @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 @@ -5574,10 +6049,10 @@ displayed as empty lines in the summary buffer. @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 @@ -5602,10 +6077,10 @@ There are four possible values: @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 @@ -5776,7 +6251,7 @@ would like to display as few summary lines as possible, but still 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. @@ -5803,7 +6278,7 @@ off sparse leaf nodes that don't lead anywhere. This variable is @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. @@ -5911,9 +6386,9 @@ meaningful. Here's one example: @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, @@ -5921,9 +6396,9 @@ remove all marks instead. If the prefix argument is negative, tick 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}). @@ -5994,8 +6469,8 @@ understand the numeric prefix. @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 @@ -6003,8 +6478,8 @@ Go to the next thread (@code{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 @@ -6172,8 +6647,8 @@ happen automatically. @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. @@ -6443,10 +6918,23 @@ Save the current article in a VM folder (@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 @@ -6494,6 +6982,13 @@ Append the article straight to an ordinary file. 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-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 @@ -6626,7 +7121,8 @@ a spool, you could @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 @@ -6643,12 +7139,12 @@ Sometime users post articles (or series of articles) that have been 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 @@ -6815,9 +7311,9 @@ doesn't really work yet. 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 @@ -7058,6 +7554,7 @@ these articles easier. * 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 @@ -7498,7 +7995,7 @@ when filling. @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 @@ -7525,6 +8022,7 @@ non-ASCII (i. e., 8-bit) articles. It typically makes strings like 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) @@ -7535,6 +8033,7 @@ Base64 is one common @sc{mime} encoding employed when sending non-ASCII 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) @@ -7546,45 +8045,11 @@ makes strings look like @samp{~@{<:Ky2;S@{#,NpJ)l6HK!#~@}}. @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) @@ -7598,6 +8063,33 @@ Add clickable buttons to the article (@code{gnus-article-add-buttons}). 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 @@ -7791,7 +8283,7 @@ Say how much time has elapsed between the article was posted and now (@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 @@ -7826,6 +8318,61 @@ that the article was posted in 1854. Although something like that is 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 @@ -7896,7 +8443,7 @@ signature after all. @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 @@ -8013,7 +8560,20 @@ To have all Vcards be ignored, you'd say something like this: @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 @@ -8040,6 +8600,42 @@ Here's an example function the does the latter: @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 @@ -8057,17 +8653,17 @@ hierarchy uses @code{iso-2022-jp-2}. @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 @@ -8141,8 +8737,9 @@ something like @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 @@ -8273,7 +8870,7 @@ The current select method will be used when fetching by 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 @@ -8294,12 +8891,13 @@ then ask Deja if that fails: (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 @@ -8502,6 +9100,14 @@ have several windows displayed side-by-side in a frame and the tree 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 @@ -8556,7 +9162,7 @@ following to your @file{.gnus.el} file: (article 1.0)))) @end lisp -@xref{Windows Configuration}. +@xref{Window Layout}. @node Mail Group Commands @@ -8574,11 +9180,13 @@ process/prefix convention (@pxref{Process/Prefix}). @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} @@ -8600,7 +9208,7 @@ disk forever and ever, never to return again.'' Use with caution. @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) @@ -8699,10 +9307,10 @@ suggestions you find reasonable. (Note that @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 @@ -8756,6 +9364,22 @@ the list in one particular group: 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 @@ -8804,13 +9428,13 @@ Go to the Gnus info node (@code{gnus-info-find-node}). @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 & @@ -8870,8 +9494,8 @@ whenever you see a message that is a collection of other messages of 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 @@ -8895,14 +9519,14 @@ to have truncation switched off while reading articles. 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}). @@ -9166,16 +9790,25 @@ to you to figure out, I think. @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 @@ -9191,6 +9824,54 @@ protocols. Otherwise, ask user. @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 @@ -9200,11 +9881,11 @@ one. All the summary buffers share the same article buffer unless you 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 @@ -9329,7 +10010,7 @@ This is also the default value for this variable. @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, @@ -9355,37 +10036,62 @@ The following commands are available when you have placed point over a @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 @@ -9393,8 +10099,27 @@ do semi-manual charset stuff (see @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}). @@ -9490,41 +10215,47 @@ group. Values in parenthesis are suggested sensible values. Others are 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 @@ -9532,7 +10263,7 @@ You can, of course, write your own functions to be called from @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 @@ -9638,12 +10369,39 @@ accepts the same format specifications as that variable, with two 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 @@ -9680,14 +10438,14 @@ Message Manual}. Where the message will be posted/mailed to depends 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 @@ -9738,7 +10496,7 @@ then set the @code{gnus-post-method} to some other method: 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. @@ -9748,7 +10506,7 @@ If that's the case, Gnus will always prompt you for what method to use 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 @@ -9846,7 +10604,8 @@ determined by the @code{gnus-message-archive-group} variable. 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 @@ -9858,11 +10617,14 @@ has the default value shown above. Then setting 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 @@ -9904,8 +10666,8 @@ messages in one file per month: (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, @@ -10158,32 +10920,19 @@ To use this correctly with GPG, you'll need the following lisp code in your @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. @@ -10200,33 +10949,34 @@ personal mail group. 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 @@ -10236,13 +10986,13 @@ The different methods all have their peculiarities, of course. 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 @@ -10257,13 +11007,13 @@ To enter the server buffer, use the @kbd{^} (@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 @@ -10282,7 +11032,7 @@ variable, with some simple extensions: @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. @@ -10368,7 +11118,7 @@ servers. @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 @@ -10389,7 +11139,7 @@ Reading directly from the spool is even simpler: @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 @@ -10403,10 +11153,10 @@ look like then: (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: @@ -10437,25 +11187,30 @@ should probably look something like this: @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 @@ -10502,7 +11257,7 @@ buffer, and you should be able to enter any of the groups displayed. @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 @@ -10515,7 +11270,7 @@ directory variables are initialized from that variable, so 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 @@ -10604,15 +11359,15 @@ Remove all marks to whether Gnus was denied connection from any servers @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 @@ -10670,7 +11425,7 @@ manual page, but here are the salient facts: 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 @@ -10729,7 +11484,8 @@ The default value is @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 @@ -10737,9 +11493,9 @@ nntpd 1.5.11t, since that command chokes that server, I've been told. @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. @@ -10751,7 +11507,7 @@ regularly, you're sure to have problems with @sc{nntp} servers not 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. @@ -10780,90 +11536,106 @@ 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 @@ -10877,74 +11649,148 @@ define a server as follows: (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 @@ -11031,30 +11877,31 @@ Reading mail with a newsreader---isn't that just plain WeIrD? But of 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 @@ -11068,7 +11915,7 @@ Does this mean that all the messages that have been marked as read are 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}. @@ -11116,18 +11963,17 @@ You Do.) @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 @@ -11149,7 +11995,7 @@ last group. 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 @@ -11198,13 +12044,13 @@ arguments in a buffer narrowed to the headers of an incoming 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} 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. @@ -11224,7 +12070,7 @@ If you wish to see where the previous mail split put the messages, you 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 @@ -11245,9 +12091,9 @@ POP mail server, from a procmail directory, or from a maildir, for 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 @@ -11299,8 +12145,8 @@ Or using the default path: (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. @@ -11327,11 +12173,14 @@ Alter this script to fit find the @samp{movemail} you want to use. @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: @@ -11491,11 +12340,13 @@ from locking problems). 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 @@ -11505,6 +12356,9 @@ some reason or other, Gnus let you treat it similar to a POP server 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 @@ -11514,7 +12368,7 @@ The name of the @sc{imap} server. The default is taken from the @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 @@ -11527,13 +12381,14 @@ prompted. @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 @@ -11587,7 +12442,9 @@ after finishing the fetch. 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 @@ -11626,7 +12483,9 @@ folder after finishing the fetch. 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 @@ -11643,7 +12502,7 @@ directory source to get mail, you can specify it as in this example: @lisp (setq mail-sources - '((directory :path "/home/pavel/.Spool/" + '((directory :path "/home/pavel/.Spool/" :suffix "" :plugged t))) @end lisp @@ -11710,6 +12569,11 @@ relevant if @code{mail-source-delete-incoming} is @code{nil}. @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 @@ -11723,7 +12587,7 @@ The way to actually tell Gnus where to get new mail from is to set (@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 @@ -11748,25 +12612,25 @@ Or, if you don't want to use any of the keyword defaults: @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 @@ -11794,19 +12658,19 @@ is done). Here's and example of using these two hooks to change the 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 @@ -11817,7 +12681,7 @@ Function called to delete files. It is @code{delete-file} by default. @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 @@ -11852,7 +12716,7 @@ Let's look at an example value of this variable first: (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") @@ -11896,7 +12760,7 @@ element is @code{&}, then process all @var{split}s in the list. @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 @@ -11974,9 +12838,10 @@ string into the subject line, you have to resort to manually moving the 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) @@ -11992,11 +12857,12 @@ messages). When mail splitting is invoked, the function @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 @@ -12134,10 +13000,12 @@ by @code{gnus-group-split-update}, this function will run @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. @@ -12177,8 +13045,8 @@ deleting the mbox file, but I wouldn't do that unless I was absolutely 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 @@ -12229,7 +13097,7 @@ automatically, you can put something like the following in your 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 @@ -12286,23 +13154,43 @@ change the expiry period (@pxref{Group Parameters}). @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 @@ -12464,7 +13352,7 @@ methods: @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. @@ -12474,7 +13362,7 @@ methods: Or something like: @lisp (setq nnmail-split-methods - '(("duplicates" "^Gnus-Warning:") + '(("duplicates" "^Gnus-Warning:.*duplicate") ;; Other rules. [...])) @end lisp @@ -12489,12 +13377,12 @@ received. Think of all the fun! She'll never see any of it! Whee! @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 @@ -12504,25 +13392,25 @@ mail, which should help. @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}). @@ -12530,9 +13418,9 @@ backends are available separately. The mail backend most people use * 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 @@ -12543,7 +13431,7 @@ backends are available separately. The mail backend most people use @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. @@ -12552,16 +13440,18 @@ Virtual server settings: @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 @@ -12572,7 +13462,7 @@ into groups. @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. @@ -12581,15 +13471,17 @@ Virtual server settings: @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 @@ -12602,7 +13494,7 @@ The @dfn{nnml} spool mail format isn't compatible with any other known 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/}. @@ -12611,7 +13503,7 @@ You do not have to create any directories beforehand; Gnus will take 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, @@ -12619,10 +13511,21 @@ shouting ``Who is eating all my inodes?! Who? Who!?!'', then you should 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: @@ -12630,23 +13533,28 @@ 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 @@ -12656,6 +13564,15 @@ The name of the @sc{nov} files. The default is @file{.overview}. @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 @@ -12674,20 +13591,23 @@ Commands}). @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 @@ -12696,7 +13616,7 @@ sure that the articles in the folder are actually what Gnus thinks they 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 @@ -12706,29 +13626,45 @@ to set this variable to @code{t}. @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 @@ -12753,7 +13689,31 @@ extract some information from it before removing it. @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 @@ -12766,13 +13726,13 @@ command to make @code{nnfolder} aware of all likely files in @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 @@ -12781,11 +13741,11 @@ in the world got at Usenet by running a reader on the machine where the 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: @@ -12801,7 +13761,7 @@ to make it clear in this instance that this is not the RFC-specified @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 @@ -12831,7 +13791,7 @@ look at your mail. @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, @@ -12853,7 +13813,7 @@ tight, shared filesystems. But if you live on a personal machine where 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. @@ -12875,14 +13835,14 @@ itself puts *all* one's mail in one file; @code{nnfolder} provides a 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 @@ -12902,33 +13862,33 @@ and click, and there's the discussion. With mailing lists, you have to 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 @@ -12937,6 +13897,35 @@ cases, it makes a lot of sense to let the Gnus Agent (@pxref{Gnus 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 @@ -12953,7 +13942,7 @@ those, like, Web browsers, and you, like, have to, rilly, like, look at 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 @@ -13044,7 +14033,7 @@ following in your @file{.gnus.el} file: '((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 @@ -13083,12 +14072,12 @@ The password to use when posting. @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}. @@ -13128,7 +14117,7 @@ quite regular and nice interface, and it's possible to get the 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 @@ -13162,7 +14151,7 @@ gnus-group-make-warchive-group RET an_egroup RET egroups RET 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: @@ -13205,6 +14194,41 @@ The directory where @code{nnrss} stores its files. The default is @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 "") 'browse-nnrss-url)) +(add-to-list 'nnmail-extra-headers nnrss-url-field) +@end lisp + @node Customizing w3 @subsection Customizing w3 @cindex w3 @@ -13212,12 +14236,12 @@ The directory where @code{nnrss} stores its files. The default is @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 @@ -13235,1133 +14259,1176 @@ Put that in your @file{.emacs} file, and hitting links in w3-rendered @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 @@ -14372,8 +15439,8 @@ Gnus allows combining a mixture of all the other group types into bigger 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 @@ -14446,13 +15513,13 @@ you enter it---it'll have much the same effect. @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. @@ -14463,7 +15530,7 @@ 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! @@ -14555,16 +15622,16 @@ That's it. Gnus is now an ``offline'' newsreader. 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 @@ -14623,7 +15690,7 @@ the Agent. @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 @@ -14655,9 +15722,9 @@ Groups that do not belong in any other category belong to 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 @@ -15037,7 +16104,7 @@ Articles that have a score higher than this have a high score. Default @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. @@ -15080,9 +16147,9 @@ Fetch all eligible articles in all groups @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) @@ -15132,6 +16199,12 @@ Toggle whether to download the article (@code{gnus-agent-toggle-mark}). @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 @@ -15181,7 +16254,7 @@ unread, ticked and dormant articles will be kept indefinitely. @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. @@ -15383,22 +16456,23 @@ temporary and have not been used for, say, a week, will be removed 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 @@ -15536,7 +16610,8 @@ Score on the @code{Message-ID} header. @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. @@ -15545,7 +16620,8 @@ 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 @@ -15783,18 +16859,20 @@ can't have score files like @file{all.SCORE}, but you can have 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 @@ -15953,7 +17031,7 @@ the match, we get the score added if the article has less than 4 lines. (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. @@ -16459,6 +17537,39 @@ Whether it's the first two or first three characters that are ``yours'' 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 RET}. + +See? Simple. + + @node Scoring Tips @section Scoring Tips @cindex scoring tips @@ -16478,7 +17589,9 @@ the @code{Xref} header. 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 @@ -16544,9 +17657,10 @@ All you have to do to use other people's score files is to set the 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 @@ -16555,6 +17669,7 @@ all score files in the @file{/ftp@@ftp.some-where:/pub/score} directory: @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 @@ -16720,9 +17835,10 @@ before. @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 @@ -16734,11 +17850,14 @@ of a prediction, what they thought of the article. You can use this 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 @@ -16890,7 +18009,7 @@ Prediction +/- confidence. @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 @@ -16984,6 +18103,10 @@ simple scoring, and the match types are also the same. @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: @@ -17137,29 +18260,39 @@ the new score, which should be an integer. 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 @@ -17269,9 +18402,9 @@ same time? You can't, and you're probably perfectly happy that way. 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 @@ -17298,11 +18431,14 @@ Here's an example format spec (from the group buffer): @samp{%M%S%5y: 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: @@ -17345,6 +18481,8 @@ particularly wide values. For that you can say @samp{%4,6y}, which 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 @@ -17444,6 +18582,9 @@ be inserted into the buffer just like information from any other 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 @@ -17502,10 +18643,66 @@ and extremely vulgar displays. Have fun! 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. @@ -17606,13 +18803,13 @@ To be slightly more formal, here's a definition of what a valid split 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 @@ -17708,13 +18905,14 @@ for composing mail and news while leaving the original frame intact. To 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 @@ -17749,7 +18947,7 @@ windows resized. @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). @@ -18264,7 +19462,7 @@ never be totally undoable. @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. @@ -18314,18 +19512,18 @@ To use moderation mode in these two groups, say: @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 @@ -18343,11 +19541,11 @@ good way to do so. Its also a great way to impress people staring 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 @@ -18385,24 +19583,24 @@ obtaining and installing the picons databases, point your Web browser at @* 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 @@ -18467,7 +19665,7 @@ default (which by default maps to the buffer @samp{*Picons*}). Other 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 @@ -18491,8 +19689,9 @@ Looks up and displays the picons for the author and the author's domain 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 @@ -18536,11 +19735,13 @@ command to use to convert the @code{X-Face} header to an X bitmap (@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 @@ -18600,7 +19801,7 @@ cleared every time you exit Gnus. Defaults to @code{t}. @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 @@ -18666,6 +19867,57 @@ Face used for mouse highlighting over the smiley face. @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 @@ -18888,16 +20140,16 @@ shut up, but will flash so many messages it will make your head swim. @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}. @@ -18953,7 +20205,6 @@ group). @end table - @node The End @chapter The End @@ -18988,17 +20239,30 @@ but at the common table.@* @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 @@ -19025,15 +20289,15 @@ renamed it back again to ``Gnus''. But in mixed case. ``Gnus'' vs. ``@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 @@ -19105,8 +20369,8 @@ keep track of millions of people who post? 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. @@ -19267,7 +20531,7 @@ Emacsen. 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 @@ -19337,6 +20601,9 @@ well as numerous other things). Luis Fernandes---design and graphics. @item +Joe Reiss---creator of the smiley faces. + +@item Justin Sheehy--the FAQ maintainer. @item @@ -19627,11 +20894,11 @@ actually are people who are using Gnus. Who'd'a thunk it! @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 @@ -19658,7 +20925,7 @@ You can combine groups into virtual groups (@pxref{Virtual Groups}). @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 @@ -19746,7 +21013,7 @@ Buttons}). @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 @@ -19760,7 +21027,7 @@ 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 @@ -19847,7 +21114,7 @@ news batches, ClariNet briefs collections, and just about everything 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 @@ -19885,7 +21152,7 @@ All functions for hiding article elements are now toggles. 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}). @@ -19895,14 +21162,14 @@ All summary mode commands are available directly from the article 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 @@ -19997,7 +21264,7 @@ New features in Gnus 5.4/5.5: @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 @@ -20064,7 +21331,7 @@ There's a way now to specify that ``uninteresting'' fields be suppressed 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 @@ -20096,7 +21363,7 @@ the native server (@pxref{Changing Servers}). @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 @@ -20104,11 +21371,11 @@ Process mark sets can be pushed and popped (@pxref{Setting Process 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}). @@ -20126,7 +21393,7 @@ Cached articles can be pulled into the groups (@pxref{Summary Generation 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 @@ -20161,7 +21428,7 @@ added. A plethora of new commands and modes have been added. See @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. @@ -20270,7 +21537,7 @@ been added. 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}. @@ -20284,7 +21551,8 @@ New features in Gnus 5.8: @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 @@ -20296,7 +21564,7 @@ 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 @@ -20307,29 +21575,37 @@ this now has changed to 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 @@ -20404,16 +21680,16 @@ I guess most manuals are written after-the-fact; documenting a program 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. @@ -20448,26 +21724,26 @@ Send a mail to the person who has written what you are reading. 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 @@ -20503,7 +21779,7 @@ collection of @sc{nov} lines. @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. @@ -20550,7 +21826,7 @@ A machine one can connect to and get news (or mail) from. @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 @@ -20618,10 +21894,10 @@ section is designed to give general pointers on how to customize Gnus 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 @@ -20805,6 +22081,10 @@ it, copy the Emacs window to a file (with @code{xwd}, for instance), put 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. @@ -20826,20 +22106,20 @@ it. 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 @@ -20908,7 +22188,7 @@ Says whether @var{group} is read-only or not. @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 @@ -20949,7 +22229,7 @@ Narrows the current buffer to the body of the article. @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 @@ -20964,19 +22244,19 @@ Prompts the user for a select method. @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. @@ -20993,8 +22273,8 @@ name. Take this example: 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}, @@ -21009,37 +22289,56 @@ talk about @dfn{return value}, I talk about the function value returned by 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 @@ -21051,7 +22350,7 @@ If @var{fetch-old} is non-@code{nil} it says to try fetching "extra 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. @@ -21105,7 +22404,7 @@ For a closer look at what should be in those fields, @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. @@ -21124,8 +22423,8 @@ There should be no data returned. @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. @@ -21203,7 +22502,7 @@ info = "211 " 3* [ " " ] @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. @@ -21249,8 +22548,8 @@ There should be no result data from this function. @end table -@node Optional Backend Functions -@subsubsection Optional Backend Functions +@node Optional Back End Functions +@subsubsection Optional Back End Functions @table @code @@ -21273,8 +22572,8 @@ group-buffer = *active-line / *group-status @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. @@ -21300,7 +22599,7 @@ There should be no result data from this function. 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. @@ -21311,14 +22610,13 @@ ACTION is a list of mark setting requests, having this format: @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 @@ -21340,10 +22638,10 @@ There should be no result data from this function. @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 @@ -21357,10 +22655,10 @@ There should be no result data from this function. @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. @@ -21391,8 +22689,18 @@ description-buffer = *description-line @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) @@ -21406,7 +22714,7 @@ There should be no return data. 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. @@ -21484,9 +22792,9 @@ There should be no data returned. @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}. @@ -21499,18 +22807,18 @@ 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 @@ -21518,14 +22826,14 @@ 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 @@ -21548,8 +22856,8 @@ a public server variable. Most state-oriented variables should be 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 @@ -21562,7 +22870,7 @@ This means that @code{nnml-current-directory} will be set to 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 @@ -21572,11 +22880,11 @@ have. @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 @@ -21590,7 +22898,7 @@ third, and fourth parameters will be passed on to 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. @@ -21609,7 +22917,7 @@ defined now. @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 @@ -21634,7 +22942,9 @@ Below is a slightly shortened version of the @code{nndir} backend. "*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) @@ -21652,7 +22962,8 @@ Below is a slightly shortened version of the @code{nndir} backend. (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))) @@ -21675,15 +22986,16 @@ Below is a slightly shortened version of the @code{nndir} backend. @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: @@ -21692,36 +23004,38 @@ 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}: @@ -21739,7 +23053,7 @@ This function takes four parameters. @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 @@ -21753,15 +23067,15 @@ This optional argument should be a group name if the splitting is to be 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 @@ -21791,47 +23105,47 @@ Here's a typical score file: 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 = -string-header = "subject" / "from" / "references" / "message-id" / - "xref" / "body" / "head" / "all" / "followup" -number-header = "lines" / "chars" -date-header = "date" -string-match = "(" quote quote [ "" / [ space score [ "" / - space date [ "" / [ space string-match-t ] ] ] ] ] ")" -score = "nil" / -date = "nil" / -string-match-t = "nil" / "s" / "substring" / "S" / "Substring" / - "r" / "regex" / "R" / "Regex" / - "e" / "exact" / "E" / "Exact" / - "f" / "fuzzy" / "F" / "Fuzzy" -number-match = "(" [ "" / [ space score [ "" / - space date [ "" / [ space number-match-t ] ] ] ] ] ")" -number-match-t = "nil" / "=" / "<" / ">" / ">=" / "<=" -date-match = "(" quote 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" / -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 = +string-header = "subject" / "from" / "references" / "message-id" / + "xref" / "body" / "head" / "all" / "followup" +number-header = "lines" / "chars" +date-header = "date" +string-match = "(" quote quote [ "" / [ space score [ "" / + space date [ "" / [ space string-match-t ] ] ] ] ] ")" +score = "nil" / +date = "nil" / +string-match-t = "nil" / "s" / "substring" / "S" / "Substring" / + "r" / "regex" / "R" / "Regex" / + "e" / "exact" / "E" / "Exact" / + "f" / "fuzzy" / "F" / "Fuzzy" +number-match = "(" [ "" / [ space score [ "" / + space date [ "" / [ space number-match-t ] ] ] ] ] ")" +number-match-t = "nil" / "=" / "<" / ">" / ">=" / "<=" +date-match = "(" quote 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" / +expunge = "expunge" space nil-or-number mark-and-expunge = "mark-and-expunge" space nil-or-number -files = "files" *[ space ] -exclude-files = "exclude-files" *[ space ] -read-only = "read-only" [ space "nil" / space "t" ] -adapt = "adapt" [ space "ignore" / space "t" / space adapt-rule ] -adapt-rule = "(" *[ *[ "(" ")" ] ")" -local = "local" *[ space "(" space
    ")" ] -eval = "eval" space -space = *[ " " / / ] +files = "files" *[ space ] +exclude-files = "exclude-files" *[ space ] +read-only = "read-only" [ space "nil" / space "t" ] +adapt = "adapt" [ space "ignore" / space "t" / space adapt-rule ] +adapt-rule = "(" *[ *[ "(" ")" ] ")" +local = "local" *[ space "(" space ")" ] +eval = "eval" space +space = *[ " " / / ] @end example Any unrecognized elements in a score file should be ignored, but not @@ -22172,8 +23486,8 @@ hit these indirections impose on Gnus under XEmacs should be slight. @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 @@ -22198,9 +23512,9 @@ Here's a pseudo-BNF definition of this file: @example active = *group-line -group-line = group space high-number space low-number space flag +group-line = group spc high-number spc low-number spc flag group = -space = " " +spc = " " high-number = low-number = flag = "y" / "n" / "m" / "j" / "x" / "=" group @@ -22236,7 +23550,7 @@ description = 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 @@ -22244,8 +23558,8 @@ you are already familiar with Emacs, just ignore this and go fondle your 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 @@ -22276,11 +23590,11 @@ which is the meta key on this keyboard. It's usually located somewhere 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 @@ -22371,9 +23685,12 @@ former). The manual is unambiguous, but it can be confusing. @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 diff --git a/texi/gnusconfig.tex.in b/texi/gnusconfig.tex.in new file mode 100644 index 0000000..4989104 --- /dev/null +++ b/texi/gnusconfig.tex.in @@ -0,0 +1,11 @@ +@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: diff --git a/texi/gnuslogo-refcard.eps b/texi/gnuslogo-refcard.eps new file mode 100644 index 0000000..41f1979 --- /dev/null +++ b/texi/gnuslogo-refcard.eps @@ -0,0 +1,242 @@ +%!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 diff --git a/texi/gnusref.tex b/texi/gnusref.tex index b8e863d..b8b270f 100644 --- a/texi/gnusref.tex +++ b/texi/gnusref.tex @@ -1,16 +1,16 @@ -% -*- 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 @@ -24,13 +24,15 @@ \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).\\* @@ -78,13 +80,20 @@ \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} @@ -519,7 +528,7 @@ \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.\\ @@ -711,7 +720,8 @@ /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.\\ @@ -955,16 +965,16 @@ \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} } } @@ -1039,3 +1049,8 @@ \end{keys} } } + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: "refcard.tex" +%%% End: diff --git a/texi/herds/convol11.pnm b/texi/herds/convol11.pnm new file mode 100644 index 0000000..2f21812 --- /dev/null +++ b/texi/herds/convol11.pnm @@ -0,0 +1,14 @@ +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 diff --git a/texi/herds/convol5.pnm b/texi/herds/convol5.pnm new file mode 100644 index 0000000..e164bd9 --- /dev/null +++ b/texi/herds/convol5.pnm @@ -0,0 +1,8 @@ +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 diff --git a/texi/herds/gnus-herd-bw.png b/texi/herds/gnus-herd-bw.png new file mode 100644 index 0000000..8ed5904 Binary files /dev/null and b/texi/herds/gnus-herd-bw.png differ diff --git a/texi/herds/gnus-herd-new.png b/texi/herds/gnus-herd-new.png new file mode 100644 index 0000000..b0dacd1 Binary files /dev/null and b/texi/herds/gnus-herd-new.png differ diff --git a/texi/herds/new-herd-1.png b/texi/herds/new-herd-1.png new file mode 100644 index 0000000..775d493 Binary files /dev/null and b/texi/herds/new-herd-1.png differ diff --git a/texi/herds/new-herd-2.png b/texi/herds/new-herd-2.png new file mode 100644 index 0000000..19b2fbc Binary files /dev/null and b/texi/herds/new-herd-2.png differ diff --git a/texi/herds/new-herd-3.png b/texi/herds/new-herd-3.png new file mode 100644 index 0000000..1d36d23 Binary files /dev/null and b/texi/herds/new-herd-3.png differ diff --git a/texi/herds/new-herd-4.png b/texi/herds/new-herd-4.png new file mode 100644 index 0000000..23ccb23 Binary files /dev/null and b/texi/herds/new-herd-4.png differ diff --git a/texi/herds/new-herd-5.png b/texi/herds/new-herd-5.png new file mode 100644 index 0000000..aa85f31 Binary files /dev/null and b/texi/herds/new-herd-5.png differ diff --git a/texi/herds/new-herd-6.png b/texi/herds/new-herd-6.png new file mode 100644 index 0000000..df103ed Binary files /dev/null and b/texi/herds/new-herd-6.png differ diff --git a/texi/herds/new-herd-7.png b/texi/herds/new-herd-7.png new file mode 100644 index 0000000..c5e29a7 Binary files /dev/null and b/texi/herds/new-herd-7.png differ diff --git a/texi/herds/new-herd-8.png b/texi/herds/new-herd-8.png new file mode 100644 index 0000000..94dea5a Binary files /dev/null and b/texi/herds/new-herd-8.png differ diff --git a/texi/herds/new-herd-9.png b/texi/herds/new-herd-9.png new file mode 100644 index 0000000..dc26eb4 Binary files /dev/null and b/texi/herds/new-herd-9.png differ diff --git a/texi/herds/new-herd-section.png b/texi/herds/new-herd-section.png new file mode 100644 index 0000000..662a982 Binary files /dev/null and b/texi/herds/new-herd-section.png differ diff --git a/texi/herds/new-herd.png b/texi/herds/new-herd.png new file mode 100644 index 0000000..c021e9b Binary files /dev/null and b/texi/herds/new-herd.png differ diff --git a/texi/herds/new-herd2.png b/texi/herds/new-herd2.png new file mode 100644 index 0000000..6e1a8fd Binary files /dev/null and b/texi/herds/new-herd2.png differ diff --git a/texi/infohack.el b/texi/infohack.el index 0fa6af0..4fe9949 100644 --- a/texi/infohack.el +++ b/texi/infohack.el @@ -30,12 +30,19 @@ (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. @@ -43,6 +50,7 @@ (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))) diff --git a/texi/message.texi b/texi/message.texi index 5a05ddd..f47b81a 100644 --- a/texi/message.texi +++ b/texi/message.texi @@ -18,7 +18,7 @@ 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 @@ -351,8 +351,9 @@ times, you will get back the un-edited message you're responding to. @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 @@ -416,6 +417,27 @@ Go to the @code{Keywords} header (@code{message-goto-keywords}). @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 @@ -434,6 +456,13 @@ Move to the beginning of the body of the message @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 @@ -448,8 +477,8 @@ Move to the signature of the message (@code{message-goto-signature}). 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}). @@ -476,88 +505,6 @@ Insert the message headers (@code{message-insert-headers}). @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 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 @@ -584,15 +531,17 @@ Manual}). @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 @@ -602,6 +551,12 @@ a MIME part is done using the @code{C-c C-m s} key map for signing and the 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 @@ -614,6 +569,12 @@ Digitally sign current MIME part using PGP/MIME. 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 @@ -653,7 +614,7 @@ modern cryptography, S/MIME, various PKCS standards, OpenSSL and so on. 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 @@ -703,9 +664,9 @@ care in handling it. @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 @@ -746,7 +707,7 @@ Delete all text in the body of the message that is outside the region @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: @@ -901,6 +862,7 @@ installed. * 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. @@ -971,6 +933,9 @@ 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 @@ -981,6 +946,14 @@ have to deal with users that use these evil tools, in which case you may 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 @@ -1018,9 +991,15 @@ buffers that are initialized as mail. @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 @@ -1238,6 +1217,111 @@ posting a prepared news message. @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 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 @@ -1381,7 +1465,7 @@ the mailed copy. If the string contains the format spec @samp{%s}, the 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 diff --git a/texi/misc/ered.tif b/texi/misc/ered.tif new file mode 100644 index 0000000..4b64018 Binary files /dev/null and b/texi/misc/ered.tif differ diff --git a/texi/misc/eseptember.tif b/texi/misc/eseptember.tif new file mode 100644 index 0000000..b75ae6c Binary files /dev/null and b/texi/misc/eseptember.tif differ diff --git a/texi/misc/fred.tif b/texi/misc/fred.tif new file mode 100644 index 0000000..e04f262 Binary files /dev/null and b/texi/misc/fred.tif differ diff --git a/texi/misc/fseptember.tif b/texi/misc/fseptember.tif new file mode 100644 index 0000000..6583c2b Binary files /dev/null and b/texi/misc/fseptember.tif differ diff --git a/texi/misc/larsi.png b/texi/misc/larsi.png new file mode 100644 index 0000000..d8b5b27 Binary files /dev/null and b/texi/misc/larsi.png differ diff --git a/texi/misc/red.png b/texi/misc/red.png new file mode 100644 index 0000000..e646e00 Binary files /dev/null and b/texi/misc/red.png differ diff --git a/texi/misc/red.ps b/texi/misc/red.ps new file mode 100644 index 0000000..26148e9 --- /dev/null +++ b/texi/misc/red.ps @@ -0,0 +1,2809 @@ +%!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 diff --git a/texi/misc/september.png b/texi/misc/september.png new file mode 100644 index 0000000..1e5539e Binary files /dev/null and b/texi/misc/september.png differ diff --git a/texi/pagestyle.sty b/texi/pagestyle.sty index ffd4529..d434821 100644 --- a/texi/pagestyle.sty +++ b/texi/pagestyle.sty @@ -1,14 +1,13 @@ -\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} @@ -44,17 +43,17 @@ \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 @@ -82,4 +81,3 @@ \setcounter{tocdepth}{3} \setcounter{secnumdepth}{3} -\def\verbatim@font{\fontfamily{bcr}\fontsize{10pt}{10}\selectfont} diff --git a/texi/picons/att.png b/texi/picons/att.png new file mode 100644 index 0000000..f0473ee Binary files /dev/null and b/texi/picons/att.png differ diff --git a/texi/picons/berkeley.png b/texi/picons/berkeley.png new file mode 100644 index 0000000..e22efcb Binary files /dev/null and b/texi/picons/berkeley.png differ diff --git a/texi/picons/caltech.png b/texi/picons/caltech.png new file mode 100644 index 0000000..68ae3e9 Binary files /dev/null and b/texi/picons/caltech.png differ diff --git a/texi/picons/canada.png b/texi/picons/canada.png new file mode 100644 index 0000000..2c747a8 Binary files /dev/null and b/texi/picons/canada.png differ diff --git a/texi/picons/cr.png b/texi/picons/cr.png new file mode 100644 index 0000000..d53d2db Binary files /dev/null and b/texi/picons/cr.png differ diff --git a/texi/picons/cygnus.xbm b/texi/picons/cygnus.xbm new file mode 100644 index 0000000..c69b5ae --- /dev/null +++ b/texi/picons/cygnus.xbm @@ -0,0 +1,27 @@ +#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}; diff --git a/texi/picons/gnu.xbm b/texi/picons/gnu.xbm new file mode 100644 index 0000000..b540df5 --- /dev/null +++ b/texi/picons/gnu.xbm @@ -0,0 +1,27 @@ +#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}; diff --git a/texi/picons/gov.xbm b/texi/picons/gov.xbm new file mode 100644 index 0000000..99f2449 --- /dev/null +++ b/texi/picons/gov.xbm @@ -0,0 +1,27 @@ +#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}; diff --git a/texi/picons/laurie.png b/texi/picons/laurie.png new file mode 100644 index 0000000..0793f9a Binary files /dev/null and b/texi/picons/laurie.png differ diff --git a/texi/picons/mit.png b/texi/picons/mit.png new file mode 100644 index 0000000..e297591 Binary files /dev/null and b/texi/picons/mit.png differ diff --git a/texi/picons/nasa.png b/texi/picons/nasa.png new file mode 100644 index 0000000..1679857 Binary files /dev/null and b/texi/picons/nasa.png differ diff --git a/texi/picons/qmw.xbm b/texi/picons/qmw.xbm new file mode 100644 index 0000000..1eb5621 --- /dev/null +++ b/texi/picons/qmw.xbm @@ -0,0 +1,27 @@ +#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}; diff --git a/texi/picons/rms.png b/texi/picons/rms.png new file mode 100644 index 0000000..10dfc25 Binary files /dev/null and b/texi/picons/rms.png differ diff --git a/texi/picons/ruu.xbm b/texi/picons/ruu.xbm new file mode 100644 index 0000000..c44ebcb --- /dev/null +++ b/texi/picons/ruu.xbm @@ -0,0 +1,27 @@ +#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}; diff --git a/texi/picons/seuu.xbm b/texi/picons/seuu.xbm new file mode 100644 index 0000000..341f175 --- /dev/null +++ b/texi/picons/seuu.xbm @@ -0,0 +1,27 @@ +#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}; diff --git a/texi/picons/stanford.png b/texi/picons/stanford.png new file mode 100644 index 0000000..b3f5dec Binary files /dev/null and b/texi/picons/stanford.png differ diff --git a/texi/picons/sun.png b/texi/picons/sun.png new file mode 100644 index 0000000..f010f16 Binary files /dev/null and b/texi/picons/sun.png differ diff --git a/texi/picons/ubc.xbm b/texi/picons/ubc.xbm new file mode 100644 index 0000000..51dda39 --- /dev/null +++ b/texi/picons/ubc.xbm @@ -0,0 +1,27 @@ +#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}; diff --git a/texi/picons/ufl.png b/texi/picons/ufl.png new file mode 100644 index 0000000..9521710 Binary files /dev/null and b/texi/picons/ufl.png differ diff --git a/texi/picons/uio.png b/texi/picons/uio.png new file mode 100644 index 0000000..66ff8b0 Binary files /dev/null and b/texi/picons/uio.png differ diff --git a/texi/picons/unit.png b/texi/picons/unit.png new file mode 100644 index 0000000..1dea18d Binary files /dev/null and b/texi/picons/unit.png differ diff --git a/texi/picons/upenn.xbm b/texi/picons/upenn.xbm new file mode 100644 index 0000000..c9b8894 --- /dev/null +++ b/texi/picons/upenn.xbm @@ -0,0 +1,27 @@ +#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}; diff --git a/texi/picons/wesleyan.xbm b/texi/picons/wesleyan.xbm new file mode 100644 index 0000000..e3b7a86 --- /dev/null +++ b/texi/picons/wesleyan.xbm @@ -0,0 +1,27 @@ +#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}; diff --git a/texi/picons/yale.xbm b/texi/picons/yale.xbm new file mode 100644 index 0000000..9915964 --- /dev/null +++ b/texi/picons/yale.xbm @@ -0,0 +1,27 @@ +#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}; diff --git a/texi/postamble.tex b/texi/postamble.tex index a7d0a5c..f4f6bf3 100644 --- a/texi/postamble.tex +++ b/texi/postamble.tex @@ -31,16 +31,20 @@ at the altar of Emacs, he can often be found slouching on his couch 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: diff --git a/texi/ps/.cvsignore b/texi/ps/.cvsignore new file mode 100644 index 0000000..2eedd36 --- /dev/null +++ b/texi/ps/.cvsignore @@ -0,0 +1,3 @@ +*.ps +*.pdf +Makefile diff --git a/texi/ps/Makefile.in b/texi/ps/Makefile.in new file mode 100644 index 0000000..644ad50 --- /dev/null +++ b/texi/ps/Makefile.in @@ -0,0 +1,213 @@ +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: diff --git a/texi/ps/gnus-big-logo.eps b/texi/ps/gnus-big-logo.eps index 88ea3b8..ea713d8 100644 --- a/texi/ps/gnus-big-logo.eps +++ b/texi/ps/gnus-big-logo.eps @@ -7,7 +7,6 @@ %%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. diff --git a/texi/ps/gnus-head.eps b/texi/ps/gnus-head.eps index 82206f8..cb74c10 100644 --- a/texi/ps/gnus-head.eps +++ b/texi/ps/gnus-head.eps @@ -7,7 +7,6 @@ %%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. diff --git a/texi/refcard.tex b/texi/refcard.tex index 5e5731f..3ef0339 100644 --- a/texi/refcard.tex +++ b/texi/refcard.tex @@ -1,22 +1,27 @@ -% -*- 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), @@ -68,12 +73,13 @@ \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} @@ -185,4 +191,6 @@ \end{document} - +%%% Local Variables: +%%% mode: latex +%%% End: diff --git a/texi/screen/group-topic.png b/texi/screen/group-topic.png new file mode 100644 index 0000000..6f4ad01 Binary files /dev/null and b/texi/screen/group-topic.png differ diff --git a/texi/screen/group.png b/texi/screen/group.png new file mode 100644 index 0000000..4b4620f Binary files /dev/null and b/texi/screen/group.png differ diff --git a/texi/screen/server.png b/texi/screen/server.png new file mode 100644 index 0000000..67f2bd4 Binary files /dev/null and b/texi/screen/server.png differ diff --git a/texi/screen/summary-adopt.png b/texi/screen/summary-adopt.png new file mode 100644 index 0000000..54e508f Binary files /dev/null and b/texi/screen/summary-adopt.png differ diff --git a/texi/screen/summary-article-c-ug.png b/texi/screen/summary-article-c-ug.png new file mode 100644 index 0000000..8f224bf Binary files /dev/null and b/texi/screen/summary-article-c-ug.png differ diff --git a/texi/screen/summary-article.png b/texi/screen/summary-article.png new file mode 100644 index 0000000..d265dca Binary files /dev/null and b/texi/screen/summary-article.png differ diff --git a/texi/screen/summary-dummy.png b/texi/screen/summary-dummy.png new file mode 100644 index 0000000..308f244 Binary files /dev/null and b/texi/screen/summary-dummy.png differ diff --git a/texi/screen/summary-empty.png b/texi/screen/summary-empty.png new file mode 100644 index 0000000..2f2ec6a Binary files /dev/null and b/texi/screen/summary-empty.png differ diff --git a/texi/screen/summary-none.png b/texi/screen/summary-none.png new file mode 100644 index 0000000..9f8f43e Binary files /dev/null and b/texi/screen/summary-none.png differ diff --git a/texi/screen/summary-unthreaded.png b/texi/screen/summary-unthreaded.png new file mode 100644 index 0000000..2e5ddbb Binary files /dev/null and b/texi/screen/summary-unthreaded.png differ diff --git a/texi/screen/summary.png b/texi/screen/summary.png new file mode 100644 index 0000000..7cfcc0e Binary files /dev/null and b/texi/screen/summary.png differ diff --git a/texi/sieve.texi b/texi/sieve.texi new file mode 100644 index 0000000..a2bfd7e --- /dev/null +++ b/texi/sieve.texi @@ -0,0 +1,379 @@ +\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 to create a new script. + + ACTIVE .sieve + template.siv +@end example + +One of the scripts are highlighted, and standard point navigation +commands (@kbd{}, @kbd{} 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: diff --git a/texi/smilies/BigFace.tif b/texi/smilies/BigFace.tif new file mode 100644 index 0000000..e073e01 Binary files /dev/null and b/texi/smilies/BigFace.tif differ diff --git a/texi/smilies/FaceAngry.xpm b/texi/smilies/FaceAngry.xpm new file mode 100644 index 0000000..32fec93 --- /dev/null +++ b/texi/smilies/FaceAngry.xpm @@ -0,0 +1,20 @@ +/* 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 ....", diff --git a/texi/smilies/FaceDevilish.xpm b/texi/smilies/FaceDevilish.xpm new file mode 100644 index 0000000..ee88aed --- /dev/null +++ b/texi/smilies/FaceDevilish.xpm @@ -0,0 +1,20 @@ +/* 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 ....", diff --git a/texi/smilies/FaceGoofy.xpm b/texi/smilies/FaceGoofy.xpm new file mode 100644 index 0000000..62d7de8 --- /dev/null +++ b/texi/smilies/FaceGoofy.xpm @@ -0,0 +1,20 @@ +/* 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 ....", diff --git a/texi/smilies/FaceGrinning.xpm b/texi/smilies/FaceGrinning.xpm new file mode 100644 index 0000000..072d505 --- /dev/null +++ b/texi/smilies/FaceGrinning.xpm @@ -0,0 +1,20 @@ +/* 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 ....", diff --git a/texi/smilies/FaceHappy.xpm b/texi/smilies/FaceHappy.xpm new file mode 100644 index 0000000..07f1214 --- /dev/null +++ b/texi/smilies/FaceHappy.xpm @@ -0,0 +1,20 @@ +/* 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 ....", diff --git a/texi/smilies/FaceIronic.xpm b/texi/smilies/FaceIronic.xpm new file mode 100644 index 0000000..677ee25 --- /dev/null +++ b/texi/smilies/FaceIronic.xpm @@ -0,0 +1,20 @@ +/* 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 ....", diff --git a/texi/smilies/FaceKOed.xpm b/texi/smilies/FaceKOed.xpm new file mode 100644 index 0000000..ed51b19 --- /dev/null +++ b/texi/smilies/FaceKOed.xpm @@ -0,0 +1,20 @@ +/* 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 ....", diff --git a/texi/smilies/FaceNyah.xpm b/texi/smilies/FaceNyah.xpm new file mode 100644 index 0000000..320cfe0 --- /dev/null +++ b/texi/smilies/FaceNyah.xpm @@ -0,0 +1,20 @@ +/* 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.", diff --git a/texi/smilies/FaceSad.xpm b/texi/smilies/FaceSad.xpm new file mode 100644 index 0000000..ced9a02 --- /dev/null +++ b/texi/smilies/FaceSad.xpm @@ -0,0 +1,20 @@ +/* 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 ....", diff --git a/texi/smilies/FaceStartled.xpm b/texi/smilies/FaceStartled.xpm new file mode 100644 index 0000000..75739c9 --- /dev/null +++ b/texi/smilies/FaceStartled.xpm @@ -0,0 +1,20 @@ +/* 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 ....", diff --git a/texi/smilies/FaceStraight.xpm b/texi/smilies/FaceStraight.xpm new file mode 100644 index 0000000..4298065 --- /dev/null +++ b/texi/smilies/FaceStraight.xpm @@ -0,0 +1,20 @@ +/* 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 ....", diff --git a/texi/smilies/FaceTalking.xpm b/texi/smilies/FaceTalking.xpm new file mode 100644 index 0000000..2295be8 --- /dev/null +++ b/texi/smilies/FaceTalking.xpm @@ -0,0 +1,20 @@ +/* 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 ....", diff --git a/texi/smilies/FaceTasty.xpm b/texi/smilies/FaceTasty.xpm new file mode 100644 index 0000000..968e493 --- /dev/null +++ b/texi/smilies/FaceTasty.xpm @@ -0,0 +1,20 @@ +/* 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 ....", diff --git a/texi/smilies/FaceWinking.xpm b/texi/smilies/FaceWinking.xpm new file mode 100644 index 0000000..25d62ef --- /dev/null +++ b/texi/smilies/FaceWinking.xpm @@ -0,0 +1,20 @@ +/* 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 ....", diff --git a/texi/smilies/FaceWry.xpm b/texi/smilies/FaceWry.xpm new file mode 100644 index 0000000..db6010d --- /dev/null +++ b/texi/smilies/FaceWry.xpm @@ -0,0 +1,20 @@ +/* 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 ....", diff --git a/texi/smilies/FaceYukky.xpm b/texi/smilies/FaceYukky.xpm new file mode 100644 index 0000000..0d3de33 --- /dev/null +++ b/texi/smilies/FaceYukky.xpm @@ -0,0 +1,20 @@ +/* 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.", diff --git a/texi/smilies/WideFaceAse1.xbm b/texi/smilies/WideFaceAse1.xbm new file mode 100644 index 0000000..1a5a589 --- /dev/null +++ b/texi/smilies/WideFaceAse1.xbm @@ -0,0 +1,19 @@ +#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}; diff --git a/texi/smilies/WideFaceAse2.xbm b/texi/smilies/WideFaceAse2.xbm new file mode 100644 index 0000000..4c7fcb6 --- /dev/null +++ b/texi/smilies/WideFaceAse2.xbm @@ -0,0 +1,19 @@ +#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}; diff --git a/texi/smilies/WideFaceAse3.xbm b/texi/smilies/WideFaceAse3.xbm new file mode 100644 index 0000000..0960e77 --- /dev/null +++ b/texi/smilies/WideFaceAse3.xbm @@ -0,0 +1,20 @@ +#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 +}; diff --git a/texi/smilies/WideFaceSmile.xbm b/texi/smilies/WideFaceSmile.xbm new file mode 100644 index 0000000..c4cc3bc --- /dev/null +++ b/texi/smilies/WideFaceSmile.xbm @@ -0,0 +1,19 @@ +#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}; diff --git a/texi/smilies/WideFaceWeep.xbm b/texi/smilies/WideFaceWeep.xbm new file mode 100644 index 0000000..4353148 --- /dev/null +++ b/texi/smilies/WideFaceWeep.xbm @@ -0,0 +1,20 @@ +#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 +}; diff --git a/texi/splitindex b/texi/splitindex index 956ad3d..cfd568c 100755 --- a/texi/splitindex +++ b/texi/splitindex @@ -1,6 +1,6 @@ #!/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 diff --git a/texi/texi2latex.el b/texi/texi2latex.el index f5cb162..a53e6f5 100644 --- a/texi/texi2latex.el +++ b/texi/texi2latex.el @@ -35,9 +35,12 @@ "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) @@ -62,6 +65,12 @@ (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))) @@ -96,15 +105,24 @@ "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 '("*")) @@ -114,7 +132,8 @@ (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)) @@ -190,7 +209,9 @@ (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))) @@ -207,7 +228,12 @@ (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 @@ -215,13 +241,19 @@ ;; "\\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" @@ -242,7 +274,13 @@ (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{}") diff --git a/texi/xface/abrahamsen.png b/texi/xface/abrahamsen.png new file mode 100644 index 0000000..20a1206 Binary files /dev/null and b/texi/xface/abrahamsen.png differ diff --git a/texi/xface/aichner.png b/texi/xface/aichner.png new file mode 100644 index 0000000..1636565 Binary files /dev/null and b/texi/xface/aichner.png differ diff --git a/texi/xface/blanks.png b/texi/xface/blanks.png new file mode 100644 index 0000000..0776a29 Binary files /dev/null and b/texi/xface/blanks.png differ diff --git a/texi/xface/cosgriff.png b/texi/xface/cosgriff.png new file mode 100644 index 0000000..59acc3f Binary files /dev/null and b/texi/xface/cosgriff.png differ diff --git a/texi/xface/drazen.png b/texi/xface/drazen.png new file mode 100644 index 0000000..dffeffe Binary files /dev/null and b/texi/xface/drazen.png differ diff --git a/texi/xface/gertzfield.png b/texi/xface/gertzfield.png new file mode 100644 index 0000000..576789e Binary files /dev/null and b/texi/xface/gertzfield.png differ diff --git a/texi/xface/goldberg.png b/texi/xface/goldberg.png new file mode 100644 index 0000000..e2fe139 Binary files /dev/null and b/texi/xface/goldberg.png differ diff --git a/texi/xface/graf.png b/texi/xface/graf.png new file mode 100644 index 0000000..d2e19d3 Binary files /dev/null and b/texi/xface/graf.png differ diff --git a/texi/xface/hardaker.png b/texi/xface/hardaker.png new file mode 100644 index 0000000..ac88bd8 Binary files /dev/null and b/texi/xface/hardaker.png differ diff --git a/texi/xface/hedbor.png b/texi/xface/hedbor.png new file mode 100644 index 0000000..5672039 Binary files /dev/null and b/texi/xface/hedbor.png differ diff --git a/texi/xface/ingrand.png b/texi/xface/ingrand.png new file mode 100644 index 0000000..2403259 Binary files /dev/null and b/texi/xface/ingrand.png differ diff --git a/texi/xface/kaplan.png b/texi/xface/kaplan.png new file mode 100644 index 0000000..106bb5e Binary files /dev/null and b/texi/xface/kaplan.png differ diff --git a/texi/xface/karlheg.png b/texi/xface/karlheg.png new file mode 100644 index 0000000..022eb68 Binary files /dev/null and b/texi/xface/karlheg.png differ diff --git a/texi/xface/kleinpaste.png b/texi/xface/kleinpaste.png new file mode 100644 index 0000000..e25e698 Binary files /dev/null and b/texi/xface/kleinpaste.png differ diff --git a/texi/xface/kyle.png b/texi/xface/kyle.png new file mode 100644 index 0000000..7354ebc Binary files /dev/null and b/texi/xface/kyle.png differ diff --git a/texi/xface/love.png b/texi/xface/love.png new file mode 100644 index 0000000..cc28c3b Binary files /dev/null and b/texi/xface/love.png differ diff --git a/texi/xface/moll.png b/texi/xface/moll.png new file mode 100644 index 0000000..b50e97f Binary files /dev/null and b/texi/xface/moll.png differ diff --git a/texi/xface/niksic.png b/texi/xface/niksic.png new file mode 100644 index 0000000..9e3839a Binary files /dev/null and b/texi/xface/niksic.png differ diff --git a/texi/xface/olsen.png b/texi/xface/olsen.png new file mode 100644 index 0000000..45df40e Binary files /dev/null and b/texi/xface/olsen.png differ diff --git a/texi/xface/patch.png b/texi/xface/patch.png new file mode 100644 index 0000000..33af321 Binary files /dev/null and b/texi/xface/patch.png differ diff --git a/texi/xface/petersen.png b/texi/xface/petersen.png new file mode 100644 index 0000000..2a83017 Binary files /dev/null and b/texi/xface/petersen.png differ diff --git a/texi/xface/pjf.png b/texi/xface/pjf.png new file mode 100644 index 0000000..e3d7f09 Binary files /dev/null and b/texi/xface/pjf.png differ diff --git a/texi/xface/riocreux.png b/texi/xface/riocreux.png new file mode 100644 index 0000000..fa4c915 Binary files /dev/null and b/texi/xface/riocreux.png differ diff --git a/texi/xface/schauer.png b/texi/xface/schauer.png new file mode 100644 index 0000000..a776767 Binary files /dev/null and b/texi/xface/schauer.png differ diff --git a/texi/xface/simmonmt.png b/texi/xface/simmonmt.png new file mode 100644 index 0000000..b3df919 Binary files /dev/null and b/texi/xface/simmonmt.png differ diff --git a/texi/xface/simmons.png b/texi/xface/simmons.png new file mode 100644 index 0000000..39e52fd Binary files /dev/null and b/texi/xface/simmons.png differ diff --git a/texi/xface/siu.png b/texi/xface/siu.png new file mode 100644 index 0000000..d140e31 Binary files /dev/null and b/texi/xface/siu.png differ diff --git a/texi/xface/smb.png b/texi/xface/smb.png new file mode 100644 index 0000000..e890698 Binary files /dev/null and b/texi/xface/smb.png differ diff --git a/texi/xface/sobek.png b/texi/xface/sobek.png new file mode 100644 index 0000000..3c838ef Binary files /dev/null and b/texi/xface/sobek.png differ diff --git a/texi/xface/thomas.png b/texi/xface/thomas.png new file mode 100644 index 0000000..0c42c8f Binary files /dev/null and b/texi/xface/thomas.png differ diff --git a/texi/xface/valdis.png b/texi/xface/valdis.png new file mode 100644 index 0000000..715d08d Binary files /dev/null and b/texi/xface/valdis.png differ diff --git a/texi/xface/verna1.png b/texi/xface/verna1.png new file mode 100644 index 0000000..d84f149 Binary files /dev/null and b/texi/xface/verna1.png differ diff --git a/texi/xface/verna2.png b/texi/xface/verna2.png new file mode 100644 index 0000000..fc2f5e5 Binary files /dev/null and b/texi/xface/verna2.png differ diff --git a/texi/xface/yamaoka.png b/texi/xface/yamaoka.png new file mode 100644 index 0000000..f406744 Binary files /dev/null and b/texi/xface/yamaoka.png differ diff --git a/todo b/todo index e7ccdb9..5fa540a 100644 --- a/todo +++ b/todo @@ -1,6 +1,42 @@ ;; 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 . + +* 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] @@ -1461,6 +1497,8 @@ exceeding lisp nesting on huge groups. * Be able to run `J u' from summary buffers. + [Done] + * Solve the halting problem.